# Testimonials Grid Shortcode

> Adds a [testimonials] shortcode that shows testimonials as a responsive grid of quotes with the customer's name, role and star rating.

- Type: PHP
- Runs: Run everywhere
- Category: [Custom Post Types & Fields](https://wpide.com/library/category/post-types/)
- Tags: testimonials, shortcode, grid
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/testimonials-grid-shortcode/

## Code

```php
add_shortcode( 'testimonials', function ( $atts ) {
    $atts = shortcode_atts( array( 'limit' => 6, 'columns' => 3, 'orderby' => 'menu_order' ), $atts, 'testimonials' );

    if ( ! post_type_exists( 'testimonial' ) ) {
        return '';
    }

    $orderby = in_array( $atts['orderby'], array( 'menu_order', 'date', 'rand' ), true ) ? $atts['orderby'] : 'menu_order';
    $key     = 'wpide_testimonials_' . md5( wp_json_encode( $atts ) . get_option( 'wpide_testimonials_ver', '1' ) );
    $html    = 'rand' === $orderby ? false : get_transient( $key );

    if ( false !== $html ) {
        return $html;
    }

    $ids = get_posts( array(
        'post_type'      => 'testimonial',
        'posts_per_page' => min( 50, max( 1, absint( $atts['limit'] ) ) ),
        'orderby'        => 'menu_order' === $orderby ? array( 'menu_order' => 'ASC', 'date' => 'DESC' ) : $orderby,
        'fields'         => 'ids',
        'no_found_rows'  => true,
    ) );

    if ( ! $ids ) {
        return '';
    }

    $min  = (int) floor( 960 / min( 4, max( 1, absint( $atts['columns'] ) ) ) ) - 24;
    $html = '<div class="testimonials-grid" style="display:grid;gap:24px;grid-template-columns:repeat(auto-fill,minmax(min(100%,' . $min . 'px),1fr))">';

    foreach ( $ids as $id ) {
        $name   = get_post_meta( $id, '_testimonial_name', true );
        $name   = $name ? $name : get_the_title( $id );
        $role   = trim( get_post_meta( $id, '_testimonial_role', true ) . ', ' . get_post_meta( $id, '_testimonial_company', true ), ', ' );
        $rating = (int) get_post_meta( $id, '_testimonial_rating', true );
        $stars  = $rating ? '<span class="testimonial-rating" role="img" aria-label="' . esc_attr( $rating . ' out of 5 stars' ) . '">' . str_repeat( '★', $rating ) . str_repeat( '☆', 5 - $rating ) . '</span>' : '';

        $html .= '<figure class="testimonial">' . $stars
            . '<blockquote>' . wp_kses_post( wpautop( get_post_field( 'post_content', $id ) ) ) . '</blockquote>'
            . '<figcaption><strong>' . esc_html( $name ) . '</strong>' . ( $role ? '<br><span>' . esc_html( $role ) . '</span>' : '' ) . '</figcaption></figure>';
    }

    $html .= '</div>';

    if ( 'rand' !== $orderby ) {
        set_transient( $key, $html, DAY_IN_SECONDS );
    }

    return $html;
} );

// Refresh the cached grids whenever a testimonial changes.
add_action( 'clean_post_cache', function ( $post_id, $post ) {
    if ( $post && 'testimonial' === $post->post_type ) {
        update_option( 'wpide_testimonials_ver', (string) microtime( true ), false );
    }
}, 10, 2 );
```

## Notes

Works with the Testimonials post type and details meta box snippets. Use limit, columns and orderby="date|menu_order|rand".

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Testimonials Grid Shortcode" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
