0

I'm trying for hours now to find the error moving back and forth. I have a custom post type. Everything works fine until I add my custom meta box. Now suddenly the slug gets the title of one of $post->ID == '21' child pages instead its own title when creating a new custom post. It always is the title from the page with the lowest $post->ID. But when I remove my custom meta box again. Everything works fine. I may have tracked it down to the foreach but I can't see what's wrong there.

Besides this %postname% error everything's fine. The custom field gets saved correctly. I even can edit the slug manually. But that's not how it is supposed to be. Please help!


Tried it without the <form> tags now. Problem still persists.

Calling wp_reset_postdata() didn't work as well. But I realized the slug always gets created right after I fill the title text input. Also when I edit the custom post later and change some content the slug gets wrong again.

add_action( 'init', 'cpt_init_cases' );
function cpt_init_cases() {
  register_post_type( 'case', array(
    'labels' => array(
      'name' => __( 'Cases' ),
      'singular_name' => __( 'Case' )),
    'description' => 'Create cases to be displayed on single customer child pages',
    'public' => true,
    'menu_position' => 6,
    'rewrite' => array('slug' => 'case'),
    'supports' => array('title', 'editor', 'thumbnail', 'custom-fields')
  ));
}

/*** when I delete everything below this line slugging works as expected ***/
add_action('admin_init', 'admin_init');
function admin_init(){
    add_meta_box('refInfo-meta', 'Reference', 'reference_meta_callback', 'case', 'side', 'high');
}  

function reference_meta_callback( $post ){

  global $post;

  $custom = get_post_custom($post->ID);
  if( isset($custom['reference_id'][0]) ) {
    $reference_id = $custom['reference_id'][0];
  } else {
    $reference_id = '0';
  }

  wp_nonce_field( 'my_meta_box_nonce', 'meta_box_nonce' );

  ?>
    <form action="<?php bloginfo('url'); ?>" method="get">
      <select name="ref_id" id="ref_id">
        <option value="0" <?php selected($reference_id, '0'); ?>>- choose client -</option>

      <?php
      $args = array( 'numberposts' => -1, 'post_type' => 'page', 'post_parent' => 21);
      $posts = get_posts( $args );
      foreach( $posts as $post ) : setup_postdata( $post ); ?>
        <option value="<?php echo $post->ID; ?>" <?php selected($reference_id, $post->ID); ?>><?php the_title(); ?></option>
      <?php endforeach; ?>

      </select>
    </form>
  <?php
}  

add_action( 'save_post', 'save_reference_id' );  
function save_reference_id( $post_id ) {

  global $post;

  if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;

  if( !isset( $_POST['meta_box_nonce'] ) || !wp_verify_nonce( $_POST['meta_box_nonce'], 'my_meta_box_nonce' ) ) return;

  if( isset($_POST['ref_id']) ) {
    update_post_meta($post->ID, 'reference_id', $_POST['ref_id']);
  }
}

1 Answer 1

2

This strange behaviour is very likely to be caused by the additional form tag you're adding. The meta boxes are already encapsulated by a form, so adding one yourself in the meta box callback is unnecessary. Removing <form action="<?php bloginfo('url'); ?>" method="get"> and </form> should solve your issues.

EDIT: Seeing as this didn't solve your issues: I now see the cause for your issue. You're looping over the child posts and then setting up post data through setup_postdata. You should reset the post data after that, to ensure that no data from your child posts is being used in the rest of the meta boxes. These other meta boxes probably include the slug box, which is why the child slug is used.

Calling wp_reset_postdata at the end of your meta box should do the trick.

EDIT 2:

I'm unsure as to why wp_reset_postdata() doesn't work, but it's probably because the post data isn't in the main query object for some reason on the edit page.

Anyway, the problem does reside in the fact that you're setting up the global post object yourself through setup_postdata. After you've done this for the child posts, the slug or title field seems to be filled through a function that uses the global $post object, and is therefore filled with the child slug or title.

To fix this, you can store the old post object before calling setup_postdata, and use setup_postdata after that to restore the old post object:

function reference_meta_callback( $post ){

  global $post;

  // Store global post object
  $post_old = $post;

  $custom = get_post_custom($post->ID);
  if( isset($custom['reference_id'][0]) ) {
    $reference_id = $custom['reference_id'][0];
  } else {
    $reference_id = '0';
  }

  wp_nonce_field( 'my_meta_box_nonce', 'meta_box_nonce' );

  ?>
      <select name="ref_id" id="ref_id">
        <option value="0" <?php selected($reference_id, '0'); ?>>- choose client -</option>

      <?php
      $args = array( 'numberposts' => -1, 'post_type' => 'page', 'post_parent' => 21);
      $posts = get_posts( $args );
      foreach( $posts as $post ) : setup_postdata( $post ); ?>
        <option value="<?php echo $post->ID; ?>" <?php selected($reference_id, $post->ID); ?>><?php the_title(); ?></option>
      <?php endforeach; ?>

      </select>
  <?php
  // Restore global post object
  $post = $post_old;
  setup_postdata( $post );
} 
8
  • Thanks for reviewing. Unfortunately the behaviour still persists. The title always gets chosen from said child pages.
    – leymannx
    Commented Jun 25, 2014 at 14:02
  • I've edited my answer with a more likely explanation :-).
    – engelen
    Commented Jun 25, 2014 at 14:23
  • Thanks alot again. But even wp_reset_postdata doesn't work. But I realized, that the slug wil be created right after I filled the title text input before saving the post manually. As is some autosave is triggered.
    – leymannx
    Commented Jun 25, 2014 at 14:33
  • 1
    I've updated my answer again. Could you try the last part of my answer? I'll explain it if it works :-).
    – engelen
    Commented Jun 25, 2014 at 15:18
  • 1
    I've updated my answer with the full explanation :-).
    – engelen
    Commented Jun 25, 2014 at 15:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.