0

So I have a custom post type "Testimonial" and it's got some...interesting...behaviors. Last night, I had that type running and had created two testimonials, one of which was titled "James Blackwood."

Later, I was building a new Post, entitled "About Us" and when Wordpress (4.9.4) assigned a slug, it came up at "james-blackwood" -- and I'm at a loss here. What gives?

Here's the code for the Testimonials content type:

function testimonial_post_type() {

$labels = array(
    'name'                  => _x( 'Testimonials', 'Post Type General Name', 'text_domain' ),
    'singular_name'         => _x( 'Testimonial', 'Post Type Singular Name', 'text_domain' ),
    'menu_name'             => __( 'Testimonials', 'text_domain' ),
    'name_admin_bar'        => __( 'Testimonial', 'text_domain' ),
    'archives'              => __( 'Testimonial Archives', 'text_domain' ),
    'attributes'            => __( 'Testimonial Attributes', 'text_domain' ),
    'parent_item_colon'     => __( 'Parent Testimonial:', 'text_domain' ),
    'all_items'             => __( 'All Testimonials', 'text_domain' ),
    'add_new_item'          => __( 'Add New Testimonial', 'text_domain' ),
    'add_new'               => __( 'Add New', 'text_domain' ),
    'new_item'              => __( 'New Testimonial', 'text_domain' ),
    'edit_item'             => __( 'Edit Testimonial', 'text_domain' ),
    'update_item'           => __( 'Update Testimonial', 'text_domain' ),
    'view_item'             => __( 'View Testimonial', 'text_domain' ),
    'view_items'            => __( 'View Testimonials', 'text_domain' ),
    'search_items'          => __( 'Search Testimonial', 'text_domain' ),
    'not_found'             => __( 'Not found', 'text_domain' ),
    'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
    'featured_image'        => __( 'Background Image', 'text_domain' ),
    'set_featured_image'    => __( 'Set background image', 'text_domain' ),
    'remove_featured_image' => __( 'Remove background image', 'text_domain' ),
    'use_featured_image'    => __( 'Use as background image', 'text_domain' ),
    'insert_into_item'      => __( 'Insert into testimonial', 'text_domain' ),
    'uploaded_to_this_item' => __( 'Uploaded to this testimonial', 'text_domain' ),
    'items_list'            => __( 'Testimonials list', 'text_domain' ),
    'items_list_navigation' => __( 'Testimonials list navigation', 'text_domain' ),
    'filter_items_list'     => __( 'Filter testimonials list', 'text_domain' ),
);
$args = array(
    'label'                 => __( 'Testimonial', 'text_domain' ),
    'description'           => __( 'Creates the testimonials used throughout the site.', 'text_domain' ),
    'labels'                => $labels,
    'supports'              => array( 'title', 'editor', 'thumbnail' ),
    'hierarchical'          => false,
    'public'                => true,
    'show_ui'               => true,
    'show_in_menu'          => true,
    'menu_position'         => 20,
    'menu_icon'             => 'dashicons-editor-quote',
    'show_in_admin_bar'     => true,
    'show_in_nav_menus'     => true,
    'can_export'            => true,
    'has_archive'           => false,
    'exclude_from_search'   => true,
    'publicly_queryable'    => true,
    'query_var'             => 'testimonial_type',
    'rewrite'               => false,
    'capability_type'       => 'page',
    'show_in_rest'          => false,
);
register_post_type( 'testimonial_type', $args );

}
add_action( 'init', 'testimonial_post_type', 0 );

Associated with that is a metabox that contains a couple of extra fields:

class Testimonial_Meta_Box {
private $screens = array(
    'testimonial_type',
    );
    private $fields = array(
    array(
        'id' => 'name-of-testimonial',
        'label' => 'Name of Testimonial',
        'type' => 'text',
    ),
    array(
        'id' => 'title-of-testimonial',
        'label' => 'Title of Testimonial',
        'type' => 'text',
    ),
    array(
        'id' => 'text-color',
        'label' => 'Text Color',
        'type' => 'color',
    ),
    array(
        'id' => 'accent-color',
        'label' => 'Accent Color',
        'type' => 'color',
    ),
);

/**
 * Class construct method. Adds actions to their respective WordPress hooks.
 */
public function __construct() {
    add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
    add_action( 'save_post', array( $this, 'save_post' ) );
}

/**
 * Hooks into WordPress' add_meta_boxes function.
 * Goes through screens (post types) and adds the meta box.
 */
public function add_meta_boxes() {
    foreach ( $this->screens as $screen ) {
        add_meta_box(
            'testimonial-extra-info',
            __( 'Testimonial Extra Info', 'testimonial-metabox' ),
            array( $this, 'add_meta_box_callback' ),
            $screen,
            'normal',
            'high'
        );
    }
}

/**
 * Generates the HTML for the meta box
 * 
 * @param object $post WordPress post object
 */
public function add_meta_box_callback( $post ) {
    wp_nonce_field( 'testimonial_extra_info_data', 'testimonial_extra_info_nonce' );
    echo 'Stylize your testimonial box.';
    $this->generate_fields( $post );
}

/**
 * Generates the field's HTML for the meta box.
 */
public function generate_fields( $post ) {
    $output = '';
    foreach ( $this->fields as $field ) {
        $label = '<label for="' . $field['id'] . '">' . $field['label'] . '</label>';
        $db_value = get_post_meta( $post->ID, 'testimonial_extra_info_' . $field['id'], true );
        switch ( $field['type'] ) {
            default:
                $input = sprintf(
                    '<input %s id="%s" name="%s" type="%s" value="%s">',
                    $field['type'] !== 'color' ? 'class="regular-text"' : '',
                    $field['id'],
                    $field['id'],
                    $field['type'],
                    $db_value
                );
        }
        $output .= $this->row_format( $label, $input );
    }
    echo '<table class="form-table"><tbody>' . $output . '</tbody></table>';
}

/**
 * Generates the HTML for table rows.
 */
public function row_format( $label, $input ) {
    return sprintf(
        '<tr><th scope="row">%s</th><td>%s</td></tr>',
        $label,
        $input
    );
}
/**
 * Hooks into WordPress' save_post function
 */
public function save_post( $post_id ) {
    if ( ! isset( $_POST['testimonial_extra_info_nonce'] ) )
        return $post_id;

    $nonce = $_POST['testimonial_extra_info_nonce'];
    if ( !wp_verify_nonce( $nonce, 'testimonial_extra_info_data' ) )
        return $post_id;

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

    foreach ( $this->fields as $field ) {
        if ( isset( $_POST[ $field['id'] ] ) ) {
            switch ( $field['type'] ) {
                case 'email':
                    $_POST[ $field['id'] ] = sanitize_email( $_POST[ $field['id'] ] );
                    break;
                case 'text':
                    $_POST[ $field['id'] ] = sanitize_text_field( $_POST[ $field['id'] ] );
                    break;
            }
            update_post_meta( $post_id, 'testimonial_extra_info_' . $field['id'], $_POST[ $field['id'] ] );
        } else if ( $field['type'] === 'checkbox' ) {
            update_post_meta( $post_id, 'testimonial_extra_info_' . $field['id'], '0' );
        }
    }
}
}
new Testimonial_Meta_Box;

Here's the weird part, though -- it seems like the behavior is connected to a separate metabox that I'm including to control the appearance of some on-page "extras"... When I shut off this "Show Page Extras" metabox, the behavior described above goes away. But if the metabox is there and I check the "Show Client Testimonial" and select one of the two choices, it will substitute the slug name from the testimonial. But regardless of which of the two choices, it's always james-blackwood (the one with the lower ID). Here's the code for that metabox (which contains some jQuery):

function page_extras_get_meta( $value ) {
global $post;

$field = get_post_meta( $post->ID, $value, true );
if ( ! empty( $field ) ) {
    return is_array( $field ) ? stripslashes_deep( $field ) : stripslashes( wp_kses_decode_entities( $field ) );
} else {
    return false;
}
}

function page_extras_add_meta_box() {
add_meta_box(
    'page_extras-page-extras',
    __( 'Page Extras', 'page_extras' ),
    'page_extras_html',
    'post',
    'side',
    'core'
);
add_meta_box(
    'page_extras-page-extras',
    __( 'Page Extras', 'page_extras' ),
    'page_extras_html',
    'page',
    'side',
    'core'
);
}
add_action( 'add_meta_boxes', 'page_extras_add_meta_box' );

function page_extras_html( $post) {
wp_nonce_field( '_page_extras_nonce', 'page_extras_nonce' ); ?>

<p>Display on-page extras for this content.</p>

<p>

    <input type="checkbox" name="page_extras_show_newest_blog_posts" id="page_extras_show_newest_blog_posts" value="show-newest-blog-posts" <?php echo ( page_extras_get_meta( 'page_extras_show_newest_blog_posts' ) === 'show-newest-blog-posts' ) ? 'checked' : ''; ?>>
    <label for="page_extras_show_newest_blog_posts"><?php _e( 'Show Newest Blog Posts', 'page_extras' ); ?></label> </p>    <p>

    <input type="checkbox" name="page_extras_show_client_testimonial" id="page_extras_show_client_testimonial" value="show-client-testimonial" <?php echo ( page_extras_get_meta( 'page_extras_show_client_testimonial' ) === 'show-client-testimonial' ) ? 'checked' : ''; ?>>
    <label for="page_extras_show_client_testimonial"><?php _e( 'Show Client Testimonial', 'page_extras' ); ?></label>   </p>    <p>
    <label for="page_extras_pick_testimonial"><?php _e( 'Pick Testimonial', 'page_extras' ); ?></label><br>
    <select name="page_extras_pick_testimonial" id="page_extras_pick_testimonial" disabled>

    <!-- make a bunch of these options from the Testimonials content type -->

    <?php
    // set arguments for query
    $args = array(
        'post_type'              => array( 'testimonial_type' ),
        'post_status'            => array( 'publish' ),
        'has_password'           => false,
        'nopaging'               => true,
        'order'                  => 'DESC',
        'orderby'                => 'date',
    );

    // The Query
    $quert = new WP_Query($args);

    function FP_isSelected ($a, $b) {
        if ($a == $b) {
            echo 'SELECTED';
        }
    }

    $testimonialChosen = page_extras_get_meta('page_extras_pick_testimonial');

    // make the OPTIONS
    while ($quert->have_posts()) {
        $quert->the_post();
        $post_id = get_the_ID();
        $post_tit = get_the_title(); 
        ?>

        <option value="<?php echo $post_id ?>" <?php FP_isSelected ($post_id, $testimonialChosen);?> ><?php echo $post_tit ?></option>

    <?php } //end while loop


    ?>  
    </select>
</p>
<script>
    // testing for checkbox on page load
    if ($("#page_extras_show_client_testimonial").prop('checked') == true) {
        //if show testimonial is checked on page load, then enable the pulldown
        $("#page_extras_pick_testimonial").prop('disabled', false);
    } 

    // watch for clicks to change state
    $( "#page_extras_show_client_testimonial" ).click(function() {
    if($(this).is(':checked'))
        $("#page_extras_pick_testimonial").prop('disabled', false);
    else
        $("#page_extras_pick_testimonial").prop('disabled', true);
});

</script>

    <?php
}

function page_extras_save( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( ! isset( $_POST['page_extras_nonce'] ) || ! wp_verify_nonce( $_POST['page_extras_nonce'], '_page_extras_nonce' ) ) return;
if ( ! current_user_can( 'edit_post', $post_id ) ) return;

if ( isset( $_POST['page_extras_show_newest_blog_posts'] ) )
    update_post_meta( $post_id, 'page_extras_show_newest_blog_posts', esc_attr( $_POST['page_extras_show_newest_blog_posts'] ) );
else
    update_post_meta( $post_id, 'page_extras_show_newest_blog_posts', null );
if ( isset( $_POST['page_extras_show_client_testimonial'] ) )
    update_post_meta( $post_id, 'page_extras_show_client_testimonial', esc_attr( $_POST['page_extras_show_client_testimonial'] ) );
else
    update_post_meta( $post_id, 'page_extras_show_client_testimonial', null );
if ( isset( $_POST['page_extras_pick_testimonial'] ) )
    update_post_meta( $post_id, 'page_extras_pick_testimonial', esc_attr( $_POST['page_extras_pick_testimonial'] ) );
}
add_action( 'save_post', 'page_extras_save' );

I've been looking at this about nine different ways since about 8pm last night and I'm at a loss. I think I've overthought this. Anyone else have any ideas?

1
  • are you missing a closing bracket on your first function? class Testimonial_Meta_Box – rudtek Feb 9 '18 at 15:38
2

The problem arises from the use of the_post(), which overwrites the global $post. Use get_posts instead of WP_Query and loop over the results with a foreach:

$query = get_posts( $args );
if( $query ){
    foreach( $query as $thepost ){
        $post_id = $thepost->ID;
        $post_title = get_the_title( $thepost ); 
    }
}
1
  • That solved it! Thank you! And good to know re: the_post() versus get_posts(). I'll keep it in mind and not bug anyone on that again. 😀 – Dan B. Feb 9 '18 at 17:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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