比较WP_Query中以序列化数组形式存储的meta_value

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了比较WP_Query中以序列化数组形式存储的meta_value相关的知识,希望对你有一定的参考价值。

我有一个与自定义帖子类型相关联的元框。元框允许用户从下拉列表中选择多个选项,然后以序列化数组的形式将其保存到数据库中。如果用户仅选择一个选项,则meta_value将存储为整数,但如果用户选择多个选项,则以序列化数组的形式保存。

以下是显示和保存元框的功能

function av_add_meta_box() {

  $post_types = array( 'advertisements' );

  foreach ( $post_types as $post_type ) {

    add_meta_box(
      'avd_screen_meta_box',         // Unique ID of meta box
      'Set Screen',     // Title of meta box
      'av_display_meta_box', // Callback function
      $post_type                   // Post type
    );

  }

}
add_action( 'add_meta_boxes', 'av_add_meta_box' );

// display meta box
function av_display_meta_box( $post ) {

  $value = get_post_meta( $post->ID, '_av_meta_key', true );

  if ( isset( $values['av-meta-box'] ) ) {
        $value = esc_attr( $values['ued-av-box'][0] );
    }

  wp_nonce_field( basename( __FILE__ ), 'av_meta_box_nonce' );

  //echo "<pre>"; print_r($value) ; echo "</pre>";
  ?>
  <select id="av-meta-box" type="text" name="av-meta-box[]" multiple="multiple">
    <option value="">Select Screen</option>
    <?php $screens =  json_decode(apply_filters("av_load_screens", "all")); 
     foreach ($screens as $screen) { 
        $location_name = json_decode(apply_filters("av_load_locations", $screen->location));
        $selected = "";
        if(gettype($value) == "array"){
          $selected = (in_array($screen->id, $value))?"selected":"";
        } else{
          $selected = ($screen->id == $value)?"selected":"";
        }  ?>
        <option <?php echo $selected; ?> value="<?php echo $screen->id; ?>"><?php echo $screen->screen_name." - ".$location_name[0]->location_name." (".$location_name[0]->pin.") "; ?></option><?php
      } ?>
  </select>

<?php

}

// save meta box
function av_save_meta_box( $post_id ) {

  $is_autosave = wp_is_post_autosave( $post_id );
  $is_revision = wp_is_post_revision( $post_id );

  $is_valid_nonce = false;

  if ( isset( $_POST[ 'av_meta_box_nonce' ] ) ) {

    if ( wp_verify_nonce( $_POST[ 'av_meta_box_nonce' ], basename( __FILE__ ) ) ) {

      $is_valid_nonce = true;

    }

  }

  if ( $is_autosave || $is_revision || !$is_valid_nonce ) return;

  if ( array_key_exists( 'av-meta-box', $_POST ) ) {

    update_post_meta(
      $post_id,                                            // Post ID
      '_av_meta_key',                                // Meta key
      array_map( 'strip_tags', $_POST[ 'av-meta-box' ])// Meta value
    );

  }

}
add_action( 'save_post', 'av_save_meta_box' );

以下是我传递给WP_Query的论据

$args = array(
                'post_type' => 'advertisements',
                'meta_query' => array (
                                    'key' => '_av_meta_key',
                                    'value' => 6,
                                    'compare' => 'IN'
                                )
            );

上面的WP_Query返回具有元值6(整数)的所有帖子。但是如果meta_value存储在像a:3:{i:0;s:1:"6";i:1;s:1:"7";i:2;s:1:"8";}这样的序列化数组中会怎样

在我的例子中,post_id:20,meta_key:_av_meta_key和meta_value:a:3:{i:0; s:1:“6”; i:1; s:1:“7”; i:2; s: 1: “8”;}

我希望我的WP_Query返回id为20的帖子,meta_value为6或7或8。

答案

我建议将(多个)值保存到数据库中的多个行中,以避免从一开始就出现问题。 WordPress支持使用相同的键为自定义字段保存多个值。

您可以重写保存值的代码:

if ( array_key_exists( 'av-meta-box', $_POST ) ) {
    delete_post_meta( $post_id, '_av_meta_key' );

    $values = array_map( 'absint', $_POST[ 'av-meta-box' ] );

    foreach ( $values as $value ) {
          add_post_meta( $post_id, '_av_meta_key', $value, false );
    }
}

这样,您可以编写查询而无需担心序列化数据。从数据库中获取值很简单:

$values = get_post_meta( $post_id, '_av_meta_key', false );

PS:我建议使用custom fields plugin来避免编写重复代码。它也可以帮助您快速解决这个问题。

另一答案

使用带有序列化数据的WP_Query很难得到正确的结果。您可以尝试使用LIKE关键字而不是IN

或者,您可以使用自定义$wpdb查询来获取您要查找的内容。

global $wpdb;

$posts = $wpdb->get_results(
  $wpdb->prepare(
    "
    SELECT *
    FROM $wpdb->postmeta
    LEFT JOIN $wpdb->posts as post
    ON post.id = post_id
    WHERE post.post_type = %s
    AND meta_key = %s
    AND meta_value LIKE %s
    ",
    'advertisements',
    '_av_meta_key',
    ':"6";'
  )
);

// Check if anything was found
if( $posts !== NULL ) {
  foreach($posts as $post_info) {
    // $post_info contains all post info as object
    echo $post_info->post_title;
  }
}

您可以将:"6";所在的部分更改为您要查找的值。如果你将数字包装在:"{number}";"中,它将使搜索更好,因为这是它在你的例子中被序列化的方式,这将使它更加完全匹配

更新:为每个屏幕ID设置元键

function av_add_meta_box() {

  $post_types = array( 'advertisements' );

  foreach ( $post_types as $post_type ) {

    add_meta_box(
      'avd_screen_meta_box',         // Unique ID of meta box
      'Set Screen',     // Title of meta box
      'av_display_meta_box', // Callback function
      $post_type                   // Post type
    );

  }

}
add_action( 'add_meta_boxes', 'av_add_meta_box' );

// display meta box
function av_display_meta_box( $post ) {

  $value = get_post_meta( $post->ID, '_av_meta_key', true );

  if ( isset( $values['av-meta-box'] ) ) {
        $value = esc_attr( $values['ued-av-box'][0] );
    }

  wp_nonce_field( basename( __FILE__ ), 'av_meta_box_nonce' );

  //echo "<pre>"; print_r($value) ; echo "</pre>";
  ?>
  <select id="av-meta-box" type="text" name="av-meta-box[]" multiple="multiple">
    <option value="">Select Screen</option>
    <?php $screens =  json_decode(apply_filters("av_load_screens", "all")); 
     foreach ($screens as $screen) { 
        $location_name = json_decode(apply_filters("av_load_locations", $screen->location));
        $selected = "";
        if(gettype($value) == "array"){
          $selected = (in_array($screen->id, $value))?"selected":"";
        } else{
          $selected = ($screen->id == $value)?"selected":"";
        }  ?>
        <option <?php echo $selected; ?> value="<?php echo $screen->id; ?>"><?php echo $screen->screen_name." - ".$location_name[0]->location_name." (".$location_name[0]->pin.") "; ?></option><?php
      } ?>
  </select>

<?php

}

// save meta box
function av_save_meta_box( $post_id ) {

  $is_autosave = wp_is_post_autosave( $post_id );
  $is_revision = wp_is_post_revision( $post_id );
  $screens     = json_decode(apply_filters("av_load_screens", "all"));

  $is_valid_nonce = false;

  if ( isset( $_POST[ 'av_meta_box_nonce' ] ) ) {

    if ( wp_verify_nonce( $_POST[ 'av_meta_box_nonce' ], basename( __FILE__ ) ) ) {

      $is_valid_nonce = true;

    }

  }

  if ( $is_autosave || $is_revision || !$is_valid_nonce ) return;

  if ( array_key_exists( 'av-meta-box', $_POST ) ) {

    $selected_screens = array_map( 'absint', $_POST[ 'av-meta-box' ] );

    foreach($screens as $screen) {
      update_post_meta(
        $post_id,
        '_av_meta_key_' . $screen->id,
        in_array( $screen->id, $selected_screens ) ? 'yes' : 'no'
      );
    }

  }

}
add_action( 'save_post', 'av_save_meta_box' );

然后,当你想使用WP_Query时,你可以构建一个数组来搜索所有键并设置与OR的关系。

$meta_query = [
  'relation' => 'OR',
];

$screens    = json_decode(apply_filters("av_load_screens", "all"));

foreach($screens as $screen) {
  $meta_query[] = [
    'key'       => '_av_meta_key_' . $screen->id,
    'value'     => 'yes',
    'compare'   => '='
  ];
}

$args = array(
  'post_type'  => 'advertisements',
  'meta_query' => $meta_query,
);

以上是关于比较WP_Query中以序列化数组形式存储的meta_value的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual Studio 中以字节数组形式将 64 位双精度转换为 80 位双精度

MySQL中数组的存储

线性表--02---顺序表

为啥不应该在数据库中以纯文本形式存储密码? [复制]

您如何在 Ruby 应用程序中以树的形式跟踪“require”的完整序列和顺序?

如何在JavaScript中以以下形式转换对象数组? [重复]