Save checkboxes of a metabox with a foreach loop (invalid argument)

My advise would be to extract the query portion of your code:

function get_brands() {
  $loop_brands = array();

  wp_nonce_field( plugin_basename( __FILE__ ), 'brands-nonce-field' );

  $args = array(
      'post_type' => 'page',
      'post_parent' => 7,
      'orderby' => 'title',
      'order' => 'ASC'
  );

  $query_brands = new WP_Query($args);
  return $query_brands;
}

Then use it like this:

function brands_save_meta_box( $post_id ) {
    $loop_brands = get_brands();
    $loop_brands = wp_list_pluck($loop_brands->posts,'post_name');
    foreach ( $loop_brands as $brand ) {
        if ( brands_user_can_save( $post_id, $brand ) ) {
            if ( isset( $_POST[ $brand ] ) ) {
                update_post_meta( $post_id, $brand, $_POST[ $brand ]);
            } else {
                delete_post_meta( $post_id, $brand);
            }
        }
    }
}

That would be the first step. Unless I made a mistake the code should work exactly as before, but without the worry and mess of the global.

You can then move to a more complicated solution involving a bit of “caching” if you will:

function brands_query() {
  $loop_brands = array();

  wp_nonce_field( plugin_basename( __FILE__ ), 'brands-nonce-field' );

  $args = array(
      'post_type' => 'page',
      'post_parent' => 7,
      'orderby' => 'title',
      'order' => 'ASC'
  );

  $query_brands = new WP_Query($args);
  return $query_brands;
}

function get_brands() {
  $brands = get_option('loop_brands');
  if (empty($brands)) {
    $brands = brands_query();
    update_option('loop_brands',$brands);
  }
  return $brands;
}

And if I am reading it right, you really only need to refresh loop_brands on page save. Something like this:

function save_brands($post_id) {
  $brands = brands_query();
  update_option('loop_brands',$brands);
}
add_action('save_post_page','save_brands');

Leave a Comment