meta_query với các giá trị meta là mảng tuần tự hóa


37

Tôi đang làm việc trong một dự án trong đó tôi đang tạo một loại bài đăng tùy chỉnh và dữ liệu tùy chỉnh được nhập thông qua các hộp meta được liên kết với loại bài đăng tùy chỉnh của tôi. Vì bất kỳ lý do gì, tôi quyết định mã hóa các hộp meta theo cách mà các đầu vào trong mỗi metabox là một phần của một mảng. Chẳng hạn, tôi đang lưu trữ kinh độ và vĩ độ:

<p> 
    <label for="latitude">Latitude:</label><br /> 
    <input type="text" id="latitude" name="coordinates[latitude]" class="full-width" value="" /> 
</p> 
<p>     
    <label for="longitude">Longitude:</label><br /> 
    <input type="text" id="longitude" name="coordinates[longitude]" class="full-width" value="" /> 
</p>

Vì bất kỳ lý do gì, tôi thích ý tưởng có một mục nhập postmeta duy nhất cho mỗi metabox. Trên save_postmóc, tôi lưu dữ liệu như vậy:

update_post_meta($post_id, '_coordinates', $_POST['coordinates']);

Tôi đã làm điều này bởi vì tôi có ba metaboxes và tôi thích chỉ có 3 giá trị postmeta cho mỗi bài đăng; tuy nhiên, bây giờ tôi đã nhận ra một vấn đề tiềm năng với điều này. Tôi có thể muốn sử dụng WP_Query để chỉ rút ra một số bài đăng nhất định dựa trên các giá trị meta này. Chẳng hạn, tôi có thể muốn nhận tất cả các bài đăng có giá trị vĩ độ trên 50. Nếu tôi có dữ liệu này trong cơ sở dữ liệu riêng lẻ, có lẽ sử dụng khóalatitude , tôi sẽ làm một cái gì đó như:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '50',
            'compare' => '>'
        )
    )
 );
$query = new WP_Query( $args );

Vì tôi có vĩ độ là một phần của _coordinates postmeta, điều này sẽ không hoạt động.

Vì vậy, câu hỏi của tôi là, có cách nào để sử dụng meta_queryđể truy vấn một mảng nối tiếp như tôi có trong kịch bản này không?

Câu trả lời:


37

Không, điều đó là không thể, và thậm chí có thể nguy hiểm.

Tôi thực sự khuyên bạn nên hủy kích hoạt dữ liệu của mình và sửa đổi thói quen lưu của bạn. Một cái gì đó tương tự như vậy sẽ chuyển đổi dữ liệu của bạn sang định dạng mới:

$args = array(
    'post_type' => 'my-post-type',
    'meta_key' => '_coordinates',
    'posts_per_page' => -1
 );
$query = new WP_Query( $args );
if($query->have_posts()){
    while($query->have_posts()){
        $query->the_post();
        $c = get_post_meta($post->id,'_coordinates',true);
        add_post_meta($post->ID,'_longitude',$c['longitude']);
        add_post_meta($post->ID,'_latitude',$c['latitude']);
        delete_post_meta($post->ID,'_coordinates',$c);
    }
}

Sau đó, bạn sẽ có thể truy vấn như bạn muốn với các khóa riêng lẻ

Nếu bạn cần lưu trữ nhiều kinh độ và nhiều vĩ độ, bạn có thể lưu trữ nhiều meta bài đăng có cùng tên. Chỉ cần sử dụng tham số thứ ba củaget_post_meta và nó sẽ trả về tất cả chúng dưới dạng một mảng

Tại sao bạn không thể truy vấn bên trong dữ liệu nối tiếp?

MySQL xem nó chỉ là một chuỗi và không thể tách nó thành dữ liệu có cấu trúc. Phân tách nó thành dữ liệu có cấu trúc chính xác là những gì đoạn mã trên

Bạn có thể truy vấn các phần của ngày, nhưng điều này sẽ không đáng tin cậy, đắt tiền, chậm và rất mong manh, với rất nhiều trường hợp cạnh. Dữ liệu tuần tự không dành cho các truy vấn SQL và không được định dạng theo cách thông thường và liên tục.

Ngoài chi phí tìm kiếm chuỗi một phần, truy vấn meta bài đăng còn chậm và dữ liệu tuần tự có thể thay đổi tùy thuộc vào những thứ như độ dài của nội dung, khiến việc tìm kiếm vô cùng tốn kém, nếu không thể tùy thuộc vào giá trị bạn đang tìm kiếm

Lưu ý về Lưu trữ Bản ghi / Thực thể / Đối tượng dưới dạng Đối tượng được Nối tiếp trong Meta

Bạn có thể muốn lưu trữ một bản ghi giao dịch trong meta post hoặc một số loại cấu trúc dữ liệu khác trong meta người dùng, sau đó gặp vấn đề ở trên.

Giải pháp ở đây không phải là chia nó thành meta bài đăng riêng lẻ, mà là nhận ra nó không bao giờ nên là meta để bắt đầu, mà là một loại bài đăng tùy chỉnh. Ví dụ: nhật ký hoặc bản ghi có thể là loại bài đăng tùy chỉnh, với bài đăng gốc là phụ huynh hoặc được tham gia thông qua thuật ngữ phân loại

Đối tượng bảo mật và nối tiếp

Lưu trữ các đối tượng PHP được tuần tự hóa thông qua serializechức năng có thể nguy hiểm , điều này thật đáng tiếc vì việc truyền một đối tượng vào WordPress sẽ có nghĩa là nó được tuần tự hóa. Điều này là do khi đối tượng được tuần tự hóa, một đối tượng được tạo và tất cả các phương thức đánh thức và các hàm tạo của nó được thực thi. Điều này có vẻ không phải là một vấn đề lớn cho đến khi người dùng quản lý để lén một đầu vào được làm cẩn thận, dẫn đến thực thi mã từ xa khi dữ liệu được đọc từ cơ sở dữ liệu và được tuần tự hóa bởi WordPress.

Điều này có thể tránh được bằng cách sử dụng JSON thay vào đó, điều này cũng giúp các truy vấn dễ dàng hơn, nhưng việc lưu trữ dữ liệu chính xác và tránh dữ liệu tuần tự có cấu trúc bắt đầu dễ dàng hơn nhiều.


5
Đối với những người đi ngang qua, đừng ngừng đọc: những câu trả lời hữu ích hơn (và gần đây) được tìm thấy bên dưới
Erenor Paz

Điều gì sẽ xảy ra nếu tôi có một mảng ID để lưu - và chúng không đại diện cho một khóa khác nhau mà tôi có thể lưu chúng dưới dạng 'vĩ độ', v.v., đó chỉ là một khóa cho tất cả (chẳng hạn như khi lưu quan hệ, v.v.). Làm gì sau đó? @ giải pháp của rabni?
đào tạo

1
Bạn có thể lưu trữ khóa nhiều lần, các cặp giá trị khóa không phải là duy nhất. Đối với các mối quan hệ, đó là những gì các nguyên tắc phân loại dành cho, nếu bạn đang sử dụng meta để ánh xạ nhiều thứ vào một thứ gì đó, hãy đặt chúng vào một thuật ngữ phân loại thay thế
Tom J Nowell

24

Tôi cũng gặp phải tình huống này. Đây là những gì tôi đã làm:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => sprintf(':"%s";', $value),
            'compare' => 'LIKE'
        )
    )
);

Hy vọng điều này giúp đỡ


1
Tôi thực sự thích giải pháp này. Thật không may, điều này không được áp dụng khi đó $valuecũng là một ID. Trong trường hợp đó, tôi đề nghị tạo ra các hàm để thêm một ký tự cho mỗi phần tử mảng trước khi lưu dữ liệu và một hàm khác để xóa ký tự trước khi sử dụng dữ liệu. Wat này, i:2chỉ mục nối tiếp sẽ không bị nhầm lẫn với i:D2dữ liệu "thực". Tham số truy vấn meta sau đó sẽ trở thành 'value' => sprintf(':"D%s";', $value),và bạn sẽ giữ đúng chức năng của câu trả lời tuyệt vời này!
Erenor Paz

Giải pháp này hiệu quả với tôi
Vishal

Điều này cũng làm việc hoàn hảo cho tôi. Đã có một hoảng loạn nhỏ khi tôi thấy giải pháp được chấp nhận mặc dù
Shane Jones

@Erenor Paz, tôi vừa đăng một giải pháp hoạt động tốt với cả ID và Chuỗi: wordpress.stackexchange.com/a/299325/25264
Pablo SG Pacheco

sử dụng LIKElà một cách tuyệt vời và nhanh chóng để đưa máy chủ của bạn xuống (không đề cập đến dương tính giả) tốt hơn là bạn có một bộ nhớ đệm rất tốt.
Mark Kaplun

10

Bạn thực sự sẽ mất khả năng truy vấn dữ liệu của mình theo bất kỳ cách hiệu quả nào khi tuần tự hóa các mục vào cơ sở dữ liệu WP.

Việc tiết kiệm và đạt được hiệu suất tổng thể mà bạn nghĩ rằng bạn đang đạt được bằng cách tuần tự hóa sẽ không được chú ý ở bất kỳ mức độ lớn nào. Bạn có thể có kích thước cơ sở dữ liệu nhỏ hơn một chút nhưng chi phí giao dịch SQL sẽ rất nặng nếu bạn truy vấn các trường đó và cố gắng so sánh chúng theo bất kỳ cách hữu ích, có ý nghĩa nào.

Thay vào đó, hãy lưu tuần tự hóa cho dữ liệu mà bạn không có ý định truy vấn theo bản chất đó, nhưng thay vào đó sẽ chỉ truy cập một cách thụ động bằng lệnh gọi API WP trực tiếp get_post_meta()- từ chức năng đó bạn cũng có thể giải nén mục nhập tuần tự để truy cập các thuộc tính mảng của nó.

Trong thực tế gán giá trị đúng như trong;

$meta = get_post_meta( $post->ID, 'key', true );

Sẽ trả về dữ liệu dưới dạng một mảng, có thể truy cập để bạn lặp đi lặp lại như bình thường.

Bạn có thể tập trung vào các tối ưu hóa cơ sở dữ liệu / trang web khác như bộ nhớ đệm, thu nhỏ CSS và JS và sử dụng các dịch vụ như CDN nếu bạn yêu cầu. Đặt tên nhưng một vài .... WordPress Codex là điểm khởi đầu tốt để khám phá thêm về chủ đề đó: TẠI ĐÂY


3

Tôi vừa mới xử lý các trường nối tiếp và có thể truy vấn chúng. Không sử dụng meta_query mà sử dụng truy vấn SQL.

global $wpdb; 

$search = serialize('latitude').serialize(50);

$query = $wpdb->prepare("SELECT `post_id`
FROM `wp_postmeta`
WHERE `post_id` IN (SELECT `ID` FROM `wp_posts` WHERE `post_type` = 'my-post-type')
AND `meta_key` = '_coordinates'
AND `meta_value` LIKE '%s'",'%'.$search.'%');

$ids = $wpdb->get_col($query);

$args = array(
    'post__in' => $ids
    'post_type' => 'team' //add the type because the default will be 'post'
);

$posts = get_posts($args);

Truy vấn đầu tiên tìm kiếm bài đăng với post_type phù hợp để số lượng bản ghi wp_postmeta sẽ ít hơn để lọc. Sau đó, tôi đã thêm một câu lệnh where để giảm các hàng hơn nữa bằng cách lọc vàometa_key

Các ID kết thúc tốt đẹp trong một mảng khi cần cho get_posts.

Tái bút MySQL v5.6 trở lên là cần thiết để thực hiện truy vấn con tốt


1

Ví dụ này thực sự giúp tôi. Nó đặc biệt dành cho plugin S2Members (giúp tuần tự hóa siêu dữ liệu người dùng). Nhưng nó cho phép bạn truy vấn một phần của mảng được tuần tự hóa trong meta_key.

Nó hoạt động bằng cách sử dụng chức năng REGEXP của MySQL.

Đây là nguồn

Đây là mã truy vấn tất cả người dùng sống ở Mỹ. Tôi dễ dàng sửa đổi nó để truy vấn một trong các trường đăng ký tùy chỉnh của mình và khiến nó hoạt động nhanh chóng.

  <?php
global $wpdb;
$users = $wpdb->get_results ("SELECT `user_id` as `ID` FROM `" . $wpdb->usermeta . 
          "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_custom_fields' AND 
           `meta_value` REGEXP '.*\"country_code\";s:[0-9]+:\"US\".*'");
if (is_array ($users) && count ($users) > 0)
    {
        foreach ($users as $user)
            {
                $user = /* Get full User object now. */ new WP_User ($user->ID);
                print_r($user); /* Get a full list of properties when/if debugging. */
            }
    }
?>

1

Tôi nghĩ có 2 giải pháp có thể cố gắng giải quyết vấn đề kết quả đang được lưu trữ là cả Chuỗi và Số nguyên. Tuy nhiên, điều quan trọng cần nói, như những người khác đã chỉ ra, rằng không thể đảm bảo tính toàn vẹn của các kết quả được lưu dưới dạng Integer, vì khi các giá trị này được lưu trữ dưới dạng mảng nối tiếp, chỉ mục và các giá trị được lưu trữ chính xác với cùng một mẫu. Thí dụ:

array(37,87);

được lưu trữ dưới dạng một mảng nối tiếp, như thế này

a:2:{i:0;i:37;i:1;i:87;}

Lưu ý i:0là vị trí đầu tiên của mảng và i:37là giá trị đầu tiên. Các mô hình là như nhau. Nhưng hãy đi đến giải pháp


1) Giải pháp REGEXP

Giải pháp này hoạt động với tôi bất kể giá trị meta được lưu dưới dạng chuỗi hoặc số / id. Tuy nhiên, nó sử dụng REGEXP, không nhanh như sử dụngLIKE

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '\;i\:' . $value . '\;|\"' . $value . '\";',
            'compare' => 'REGEXP'
        )
    )
);

2) THÍCH Giải pháp

Tôi không chắc về sự khác biệt hiệu năng nhưng đây là một giải pháp sử dụng LIKEvà cũng hoạt động cho cả số và chuỗi

 $args = array(
        'post_type' => 'my-post-type',
        'meta_query' => array(
            'relation' => 'OR',
            array(
                'key' => 'latitude',
                'value' => sprintf(':"%s";', $value),
                'compare' => 'LIKE'
            ),
            array(
                'key' => 'latitude',
                'value' => sprintf(';i:%d;', $value),
                'compare' => 'LIKE'
            )
        )
    );

REGEXPlà tốt trong một số tình huống, nhưng nếu bạn có thể sử dụng LIKE, tôi nghĩ đó là phương pháp thích hợp hơn. Theo quan điểm của tôi, một liên kết cũ, nhưng vẫn khá hữu ích: Thingsilearn.wordpress.com/2008/02/11/iêu :-)
Erenor Paz

@ErenorPaz Bạn nói đúng. LIKEnhanh hơn. Nhưng đây là một giải pháp hoạt động cho cả chuỗi và số
Pablo SG Pacheco

Có..như vậy, câu trả lời là (như mọi khi): tùy thuộc vào tình huống, nếu bạn có thể sử dụng "THÍCH"; tốt hơn là, nếu không thì REGEXP cũng sẽ làm như vậy :-)
Erenor Paz

@ErenorPaz, tôi đã chỉnh sửa câu trả lời của mình bằng cách thêm một giải pháp mới sử dụng LIKEnhưng hoạt động cho cả số và chuỗi. Tôi không chắc chắn về hiệu suất vì nó phải so sánh kết quả bằng cách sử dụngOR
Pablo SG Pacheco

Chính xác !!! mà tôi cần để có được kết quả như thế này .... Cảm ơn Man !!!
kuldip Makadiya

0

Sau khi đọc một loạt các mẹo để chạy WP_Querybộ lọc theo mảng được tuần tự hóa, đây là cách cuối cùng tôi đã thực hiện: bằng cách tạo một mảng các giá trị được phân tách bằng dấu phẩy bằng cách sử dụng kết hợp với $wpdbtruy vấn SQL tùy chỉnh sử dụng FIND_IN_SETđể tìm kiếm danh sách được phân tách bằng dấu phẩy cho giá trị được yêu cầu.

(điều này tương tự như câu trả lời của Tomas, nhưng nó hơi kém hiệu năng đối với truy vấn SQL)

1. Trong hàm.php:

Trong tệp tin.php của bạn (hoặc bất cứ nơi nào bạn đang thiết lập hộp meta) trong yourname_save_post()chức năng sử dụng

update_post_meta($post->ID, 'checkboxArray', implode(",", $checkboxArray)); //adding the implode

để tạo mảng chứa các giá trị được phân tách bằng dấu phẩy.

Bạn cũng sẽ muốn thay đổi biến đầu ra của mình trong yourname_post_meta()chức năng xây dựng hộp meta của quản trị viên thành

$checkboxArray = explode(",", get_post_custom($post->ID)["checkboxArray"][0]); //adding the explode

2. Trong tệp PHP mẫu:

Kiểm tra: nếu bạn chạy một get_post_meta( $id );bạn sẽ thấy checkboxArraydưới dạng một mảng chứa các giá trị được phân tách bằng dấu phẩy thay vì một mảng được tuần tự hóa.

Bây giờ, chúng tôi xây dựng truy vấn SQL tùy chỉnh của chúng tôi bằng cách sử dụng $wpdb.

global $wpdb;

$search = $post->ID;

$query = "SELECT * FROM wp_posts
          WHERE FIND_IN_SET( $search, (
              SELECT wp_postmeta.meta_value FROM wp_postmeta
              WHERE wp_postmeta.meta_key = 'blogLocations'
              AND wp_postmeta.post_id = wp_posts.ID )
          )
          AND ( wp_posts.post_type = 'post' )
          AND ( wp_posts.post_status = 'publish' );";

$posts = $wpdb->get_results($query);

foreach ($posts as $post) {
    //your post content here
}

Lưu ý FIND_IN_SETrằng, đó là nơi phép màu xảy ra.

Bây giờ ... vì tôi đang sử dụng SELECT *điều này sẽ trả về tất cả dữ liệu bài đăng và trong phạm vi foreachbạn có thể lặp lại những gì bạn muốn từ đó (hãy làm print_r($posts);nếu bạn không biết những gì được bao gồm. Nó không thiết lập "vòng lặp" cho bạn (tôi thích nó theo cách này), nhưng nó có thể dễ dàng được sửa đổi để thiết lập vòng lặp nếu bạn thích (hãy xem setup_postdata($post);trong codex, có lẽ bạn sẽ cần phải thay đổi SELECT *để chỉ chọn ID đăng và $wpdb->get_resultsđúng $wpdbloại - - xem codex để $wpdbbiết thêm thông tin về chủ đề đó ).

Whelp, phải mất một chút nỗ lực, nhưng vì wp_querykhông hỗ trợ thực hiện 'compare' => 'IN'các giá trị được phân tách bằng dấu phẩy hoặc dấu phẩy, nên shim này là lựa chọn tốt nhất của bạn!

Hy vọng điều này sẽ giúp được ai đó.


0

Nếu bạn sử dụng liketoán tử so sánh trong truy vấn meta của mình, nó sẽ hoạt động tốt để xem bên trong một mảng được tuần tự hóa.

$wp_user_search = new WP_User_Query(array(
    'meta_query' => array(
        array(
            'key'     => 'wp_capabilities',
            'value'   => 'subscriber',
            'compare' => 'not like'
            )
        )
    )
);

kết quả trong:

[query_where] => WHERE 1=1 AND (
  ( wp_usermeta.meta_key = 'wp_capabilities' 
  AND CAST(wp_usermeta.meta_value AS CHAR) NOT LIKE '%subscriber%' )

0

Nếu dữ liệu meta của tôi là kiểu mảng, tôi sẽ sử dụng phương pháp này để truy vấn theo meta:

$args = array(
    'post_type' => 'fotobank',
    'posts_per_page' => -1,
    'meta_query' => array(
            array(
                   'key' => 'collections',
                   'value' => ':"'.$post->ID.'";',
                   'compare' => 'LIKE'
            )
     )
);
$fotos = new WP_Query($args);

Điều này có thể dẫn đến kết quả không mong muốn khi ID bài đăng có cùng giá trị với id của chuỗi được

0

Tôi tò mò về câu trả lời ở trên, nơi meta_query được nhắm mục tiêu latitudethay vì _coordinates. Phải đi và kiểm tra nếu nó thực sự có thể trong các truy vấn meta để nhắm mục tiêu một khóa cụ thể bên trong một mảng được tuần tự hóa. :)

Đó rõ ràng không phải là trường hợp.

Vì vậy, lưu ý rằng chìa khóa chính xác để nhắm mục tiêu là _coordinatesthay vì latitude.

$args = array(
     'post_type' => 'my-post-type',
     'meta_query' => array(
         array(
             'key' => '_coordinates',
             'value' => sprintf(':"%s";', $value),
             'compare' => 'LIKE'
         )
     )
 );

GHI CHÚ:

  1. Cách tiếp cận này làm cho nó chỉ có thể nhắm mục tiêu phù hợp chính xác. Vì vậy, những thứ như tất cả các vĩ độ lớn hơn 50 là không thể.

  2. Để bao gồm các kết hợp chuỗi con, người ta có thể sử dụng 'value' => sprintf(':"%%%s%%";', $value),. (chưa thử nghiệm)


-1

Tôi có cùng một câu hỏi. Có lẽ bạn cần tham số 'loại'? Kiểm tra câu hỏi liên quan này: Truy vấn trường tùy chỉnh - Meta Value là mảng

Có lẽ hãy thử:

    $ args = mảng (
    'post_type' => 'loại bài đăng của tôi',
    'meta_query' => mảng (
        mảng(
            'khóa' => 'vĩ độ',
            'giá trị' => '50 ',
            'so sánh' => '>',
            'loại' => 'số'
        )
    )
    );

Cảm ơn về lời đề nghị, nhưng đây không phải là những gì tôi đang theo đuổi. Vấn đề là giá trị tôi đang cố khớp là một phần của một mảng được tuần tự hóa trong cơ sở dữ liệu.
phímanz

Vâng, bạn đã đúng. Tôi đã thử sáng nay và nó cũng không hiệu quả với tôi. Tôi có cùng một vấn đề. Lưu trữ một giá trị của khóa meta dưới dạng một mảng. Tôi bắt đầu nghĩ rằng điều này không thể được thực hiện và thay vào đó tôi có thể phải lưu trữ chúng dưới dạng các trường meta riêng biệt có cùng tên ... và chỉ cần quản lý việc xóa / cập nhật chúng đúng cách.
user4356

@ user4356 ... đó chính xác là những gì tôi sẽ làm. Tôi đã hy vọng cắt giảm số lượng hàng mà tôi sẽ chèn cho mỗi bài viết, nhưng tôi đoán điều đó là không thể.
phímanz

-1

Tôi gặp phải điều gì đó tương tự trong khi sử dụng plugin Magic Field. Điều này có thể làm mánh khóe

$values_serialized = serialize(array('50'));
$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => $values_serialized,
            'compare' => '>'
        )
    )
);

1
Cám ơn vì sự gợi ý! Tôi nghĩ rằng điều này gần giống như người ta có thể nhận được, nhưng nó thực sự sẽ không hoạt động bởi vì so sánh một mảng được tuần tự hóa với một mảng được tuần tự hóa khác không có ý nghĩa gì trừ khi tôi đang tìm kiếm một kết hợp chính xác.
phímanz

5
Sau đó, điều này không nên được đánh dấu là câu trả lời chính xác và bạn thiếu trách nhiệm khi làm như vậy. Do đó, câu trả lời đúng sẽ là 'Không, không thể nào'
Tom J Nowell

1
Đồng ý, WP cũng xử lý việc tuần tự hóa cho bạn, serialize()không bắt buộc trong trường hợp này ...
Adam

2
Trên thực tế, câu trả lời @ seth-stevenson rất tuyệt khi thực hiện chính xác những gì anh ấy nói, sử dụng plugin "Magic Field". Vì plugin đó tuần tự hóa một số loại dữ liệu nhất định, đây là cách tốt nhất để thực hiện khớp chính xác.
zmonteca

@TomJNowell Xong! Mới lấy tôi 5 tháng;)
BOTmanz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.