Skip to content

How To Create Testimonials In WordPress With Custom Post Types

If you sell products or services online, then you must have a testimonials page on your website to show off some customers review of your service. Your customers can benefit you by giving you feedback of your work, which will boost your sales as well.

Let me show how you can create testimonials in WordPress with custom post types. Adding testimonials will be just like writing a post with all the details. This tutorials comes from Tuts+. Let’s get started.

Creating Custom Post Type

First we will create a custom post type for testimonials with archive. You can add following code to your current theme’s functions.php file or in a custom plugin:

add_action( 'init', 'testimonials_post_type' );
function testimonials_post_type() {
    $labels = array(
        'name' => 'Testimonials',
        'singular_name' => 'Testimonial',
        'add_new' => 'Add New',
        'add_new_item' => 'Add New Testimonial',
        'edit_item' => 'Edit Testimonial',
        'new_item' => 'New Testimonial',
        'view_item' => 'View Testimonial',
        'search_items' => 'Search Testimonials',
        'not_found' =>  'No Testimonials found',
        'not_found_in_trash' => 'No Testimonials in the trash',
        'parent_item_colon' => '',
    );

    register_post_type( 'testimonials', array(
        'labels' => $labels,
        'public' => true,
        'publicly_queryable' => true,
        'show_ui' => true,
        'exclude_from_search' => true,
        'query_var' => true,
        'rewrite' => true,
        'capability_type' => 'post',
        'has_archive' => true,
        'hierarchical' => false,
        'menu_position' => 10,
        'supports' => array( 'editor' ),
        'register_meta_box_cb' => 'testimonials_meta_boxes', // Callback function for custom metaboxes
    ) );
}

Now that our custom post type has been created, we will add some metaboxes to the post type using add_meta_box() and will save the metabox values with save_post action:

function testimonials_meta_boxes() {
    add_meta_box( 'testimonials_form', 'Testimonial Details', 'testimonials_form', 'testimonials', 'normal', 'high' );
}

function testimonials_form() {
    $post_id = get_the_ID();
    $testimonial_data = get_post_meta( $post_id, '_testimonial', true );
    $client_name = ( empty( $testimonial_data['client_name'] ) ) ? '' : $testimonial_data['client_name'];
    $source = ( empty( $testimonial_data['source'] ) ) ? '' : $testimonial_data['source'];
    $link = ( empty( $testimonial_data['link'] ) ) ? '' : $testimonial_data['link'];

    wp_nonce_field( 'testimonials', 'testimonials' );
    ?>
    <p>
        <label>Client's Name (optional)</label><br />
        <input type="text" value="<?php echo $client_name; ?>" name="testimonial[client_name]" size="40" />
    </p>
    <p>
        <label>Business/Site Name (optional)</label><br />
        <input type="text" value="<?php echo $source; ?>" name="testimonial[source]" size="40" />
    </p>
    <p>
        <label>Link (optional)</label><br />
        <input type="text" value="<?php echo $link; ?>" name="testimonial[link]" size="40" />
    </p>
    <?php
}

add_action( 'save_post', 'testimonials_save_post' );
function testimonials_save_post( $post_id ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;

    if ( ! empty( $_POST['testimonials'] ) && ! wp_verify_nonce( $_POST['testimonials'], 'testimonials' ) )
        return;

    if ( ! empty( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
        if ( ! current_user_can( 'edit_page', $post_id ) )
            return;
    } else {
        if ( ! current_user_can( 'edit_post', $post_id ) )
            return;
    }

    if ( ! wp_is_post_revision( $post_id ) && 'testimonials' == get_post_type( $post_id ) ) {
        remove_action( 'save_post', 'testimonials_save_post' );

        wp_update_post( array(
            'ID' => $post_id,
            'post_title' => 'Testimonial - ' . $post_id
        ) );

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

    if ( ! empty( $_POST['testimonial'] ) ) {
        $testimonial_data['client_name'] = ( empty( $_POST['testimonial']['client_name'] ) ) ? '' : sanitize_text_field( $_POST['testimonial']['client_name'] );
        $testimonial_data['source'] = ( empty( $_POST['testimonial']['source'] ) ) ? '' : sanitize_text_field( $_POST['testimonial']['source'] );
        $testimonial_data['link'] = ( empty( $_POST['testimonial']['link'] ) ) ? '' : esc_url( $_POST['testimonial']['link'] );

        update_post_meta( $post_id, '_testimonial', $testimonial_data );
    } else {
        delete_post_meta( $post_id, '_testimonial' );
    }
}

After creating the custom post type, we will add few more functions to finish the code:

add_filter( 'manage_edit-testimonials_columns', 'testimonials_edit_columns' );
function testimonials_edit_columns( $columns ) {
    $columns = array(
        'cb' => '<input type="checkbox" />',
        'title' => 'Title',
        'testimonial' => 'Testimonial',
        'testimonial-client-name' => 'Client\'s Name',
        'testimonial-source' => 'Business/Site',
        'testimonial-link' => 'Link',
        'author' => 'Posted by',
        'date' => 'Date'
    );

    return $columns;
}

add_action( 'manage_posts_custom_column', 'testimonials_columns', 10, 2 );
function testimonials_columns( $column, $post_id ) {
    $testimonial_data = get_post_meta( $post_id, '_testimonial', true );
    switch ( $column ) {
        case 'testimonial':
            the_excerpt();
            break;
        case 'testimonial-client-name':
            if ( ! empty( $testimonial_data['client_name'] ) )
                echo $testimonial_data['client_name'];
            break;
        case 'testimonial-source':
            if ( ! empty( $testimonial_data['source'] ) )
                echo $testimonial_data['source'];
            break;
        case 'testimonial-link':
            if ( ! empty( $testimonial_data['link'] ) )
                echo $testimonial_data['link'];
            break;
    }
}

/**
 * Display a testimonial
 *
 * @param  int $post_per_page  The number of testimonials you want to display
 * @param  string $orderby  The order by setting  https://codex.wordpress.org/Class_Reference/WP_Query#Order_.26_Orderby_Parameters
 * @param  array $testimonial_id  The ID or IDs of the testimonial(s), comma separated
 *
 * @return  string  Formatted HTML
 */
function get_testimonial( $posts_per_page = 1, $orderby = 'none', $testimonial_id = null ) {
    $args = array(
        'posts_per_page' => (int) $posts_per_page,
        'post_type' => 'testimonials',
        'orderby' => $orderby,
        'no_found_rows' => true,
    );
    if ( $testimonial_id )
        $args['post__in'] = array( $testimonial_id );

    $query = new WP_Query( $args  );

    $testimonials = '';
    if ( $query->have_posts() ) {
        while ( $query->have_posts() ) : $query->the_post();
            $post_id = get_the_ID();
            $testimonial_data = get_post_meta( $post_id, '_testimonial', true );
            $client_name = ( empty( $testimonial_data['client_name'] ) ) ? '' : $testimonial_data['client_name'];
            $source = ( empty( $testimonial_data['source'] ) ) ? '' : ' - ' . $testimonial_data['source'];
            $link = ( empty( $testimonial_data['link'] ) ) ? '' : $testimonial_data['link'];
            $cite = ( $link ) ? '<a href="' . esc_url( $link ) . '" target="_blank">' . $client_name . $source . '</a>' : $client_name . $source;

            $testimonials .= '<aside class="testimonial">';
            $testimonials .= '<span class="quote">&ldquo;</span>';
            $testimonials .= '<div class="entry-content">';
            $testimonials .= '<p class="testimonial-text">' . get_the_content() . '<span></span></p>';
            $testimonials .= '<p class="testimonial-client-name"><cite>' . $cite . '</cite>';
            $testimonials .= '</div>';
            $testimonials .= '</aside>';

        endwhile;
        wp_reset_postdata();
    }

    return $testimonials;
}

That’s pretty much it with custom post type. Now you can see an option to create and edit testimonials in your WordPress’ sidebar. Now, I’ll show how you can display there testimonials in the front-end of your website.

Display Testimonials Using Shortcode

That’s the easiest way to display your testimonials. You can display your testimonials using a simple [testimonials] shortcode. Just add following code:

add_shortcode( 'testimonial', 'testimonial_shortcode' );
/**
 * Shortcode to display testimonials
 *
 * [testimonial posts_per_page="1" orderby="none" testimonial_id=""]
 */
function testimonial_shortcode( $atts ) {
    extract( shortcode_atts( array(
        'posts_per_page' => '1',
        'orderby' => 'none',
        'testimonial_id' => '',
    ), $atts ) );

    return get_testimonial( $posts_per_page, $orderby, $testimonial_id );
}Code language: PHP (php)

That’s it! But wait, there’s another trick to display testimonials post type.

Display Testimonials Archive Page Template

As we have created a custom post type with archive, we can show the testimonials on the archive with a custom template. Create a file called archive-testimonials.php and add it to your current theme’s root with following code:

<?php
/**
 * Archive template for client testimonials
 */

get_header(); ?>

    <section id="primary" class="site-content">

        <div id="content" role="main">
            <header class="archive-header">
                <h1 class="archive-title">Testimonials</h1>
            </header><!-- #archive-header -->

            <?php while ( have_posts() ) : the_post();
                $testimonial_data = get_post_meta( get_the_ID(), '_testimonial', true );
                $client_name = ( empty( $testimonial_data['client_name'] ) ) ? '' : $testimonial_data['client_name'];
                $source = ( empty( $testimonial_data['source'] ) ) ? '' : ' - ' . $testimonial_data['source'];
                $link = ( empty( $testimonial_data['link'] ) ) ? '' : $testimonial_data['link'];
                $cite = ( $link ) ? '<a href="' . esc_url( $link ) . '" target="_blank">' . $client_name . $source . '</a>' : $client_name . $source;
                ?>

                <article id="post-<?php the_ID(); ?>" <?php post_class( 'testimonial' ); ?>>
                    <span class="quote">&ldquo;</span>
                    <div class="entry-content">
                        <p class="testimonial-text"><?php echo get_the_content(); ?><span></span></p>
                        <p class="testimonial-client-name"><cite><?php echo $cite; ?></cite></p>
                    </div>
                </article>

            <?php endwhile; ?>

            <?php
            global $wp_query;

            if (  1 < $wp_query->max_num_pages ) : ?>
                <nav class="archive-navigation" role="navigation">
                    <div class="nav-previous alignleft"><?php next_posts_link( '<span class="meta-nav">&larr;</span> Older posts' ); ?></div>
                    <div class="nav-next alignright"><?php previous_posts_link( 'Newer posts <span class="meta-nav">&rarr;</span>' ); ?></div>
                </nav><!-- .archive-navigation -->
                <?php
            endif;
            ?>
        </div>

    </section><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

That’s it! You can now proudly show off some great client testimonials on your WordPress website. You can also add some CSS to style the testimonials:

.testimonial {
    padding-left: 60px;
    position: relative;
    z-index: 0;
    font-size: 16px;
    }

    aside.testimonial {

        }

    .testimonial .quote {
        position: absolute;
        left: 0;
        top: -25px;
        font-size: 300px;
        font-family: Georgia, serif;
        color: #f2f2f2;
        z-index: -1;
        line-height: 1;
        }

    .testimonial-text {
        font-style: italic;
        }

    .testimonial-client-name {
        text-align: right;
        font-size: 14px;
        }

        .testimonial-client-name cite {
            font-style: normal;
            }Code language: CSS (css)

Yea, that’s wrap!

Leave a Reply

Your email address will not be published. Required fields are marked *