I have a series of CPTs, each with their own custom metaboxes. They all work great - display where they should, saving how they should. One issue I have found though is that they also ALL run their queries (for dropdown menus, etc) on EVERY admin page - and there's quite a lot.
I wrapped the section of code for the metabox options in conditional code:
function set_options() {
parent::set_options();
global $pagenow;
if ( 'post-new.php' == $pagenow || 'post.php' == $pagenow ) {
$notes_query = new WP_Query(array(
'post_type' => 'session_note',
'posts_per_page' => -1, // show all
'orderby' => 'title',
'order' => 'DESC',
'no_found_rows' => true,
'cache_results' => false,
));
$notes_options = array();
foreach ($notes_query->posts as $note) {
$notes_options[$note->ID] = get_the_title($note->ID);
}
$speaker_query = new WP_Query(array(
'post_type' => 'speaker',
'posts_per_page' => -1, // show all
'orderby' => 'title',
'order' => 'ASC',
'no_found_rows' => true,
'cache_results' => false,
));
$speaker_options = array();
foreach ($speaker_query->posts as $speaker) {
$company = get_post_meta($speaker->ID, '_conferencer_company', true);
$speaker_options[$speaker->ID] = get_the_title($speaker->ID).' – '.get_the_title($company);
}
$this->options = array_merge($this->options, array(
'note' => array(
'type' => 'multi-select',
'label' => "Special Note",
'options' => $notes_options,),
'speakers' => array(
'type' => 'multi-select',
'label' => "Presenters",
'options' => $speaker_options,),
));
}}
...which limits the code to just when you are adding or editing a post, which saves the rest of the admin from lots of unnecessary query time. The metaboxes all load fine and save fine - BUT ALL of the queries still run on ALL of the edit/add post pages, regardless of post type.
I tried limiting the queries to specific post types:
function set_options() {
parent::set_options();
global $pagenow;
if ( isset( $_GET['post_type'] )
&& $_GET['post_type'] == 'session'
&& 'post-new.php' == $pagenow || isset( $_GET['post'] )
&& 'session' == get_post_type( $_GET['post'] )
&& 'post.php' == $pagenow ) {
// do your metabox options thing - same code as above
}}
('session' is one of the CPTs)
NOW, the problem... The metaboxes still show up on the edit/add post for the specific post type as required, AND the queries for the metabox options ONLY run of the specific post type pages as well - awesome - except... The metabox fields don't save when the page is updated!
What am I missing? Do I need another $pagenow
for the updating process? If so, what is it?
EDIT
Added one of the option queries into the conditional code above as an example. Saving post/meta function below:
function save_post($post_id) {
if (get_post_type($post_id) != $this->slug) return;
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!wp_verify_nonce($_POST['conferencer_nonce'], plugin_basename(__FILE__))) return;
if (!current_user_can('edit_post', $post_id)) return;
foreach($this->options as $key => $option) {
if ($option['type'] == 'internal') continue;
$value = deep_trim($_POST['conferencer_'.$key]);
if ($option['type'] == 'int') $value = intval($value);
if ($option['type'] == 'money') $value = floatVal($value);
if ($option['type'] == 'multi-select') {
$values = array();
foreach ($_POST['conferencer_'.$key] as $value) { if (!empty($value)) $values[] = $value; }
$value = $values;
}
if ($option['type'] == 'date-time') {
$date = getdate(strtotime($_POST['conferencer_'.$key]['date']));
$time = getdate(strtotime($_POST['conferencer_'.$key]['time']));
$value = mktime($time['hours'],$time['minutes'],$time['seconds'],$date['mon'],$date['mday'],$date['year']);
}
update_post_meta($post_id, '_conferencer_'.$key, $value);
}
}
Hope that offers more insight.
$this->slug
is going to cause problems otherwise.