I have a RECIPE WP site, that is using CPTs to handle the recipe content.

The client wanted an A-Z Directory listing of all recipes. I came to Wordpress Answers and found the following code that does what I wanted:

add_shortcode('recipe_list', 'recipe_query');
function recipe_query($atts, $content){
$args = array(
    'post_type' => 'recipes',
    'orderby' => 'title',
    'order' => 'ASC',
    'posts_per_page' => -1

$query = new WP_Query( $args );

$dl = '';
$glossary_letter = '';
$active_letters = array( );

while ( $query->have_posts() ) {
$term_letter = strtoupper( substr( get_the_title(), 0, 1 ) );
if ( $glossary_letter != $term_letter ) {
    $dl .= (count( $active_letters ) ? '</ul>' : '') . '<li id="' . $term_letter . '"><span class="subheading">' . $term_letter . '</span><ul>';
    $glossary_letter = $term_letter;
    $active_letters[] = $term_letter;
$dl .= '<li><a href="'.get_permalink().'">' . get_the_title() . '</a></li>';

$dl .= '</ul></li>';

$ul = '<ul class="letters">';
foreach ( array( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ) as $letter ) {
    $ul .= '<li>' . (in_array( $letter, $active_letters ) ? '<a href="#' . $letter . '">' . $letter . '</a>' : $letter) . '</li>';
$ul .= '</ul>';

return '<div id="glossary">' . $ul . '<ul class="definitions">' . $dl . '</ul></div>';

Right now there are 1020 recipes and it seems to run slower than the other pages and since I'm a frankenstein coder (some from here and some from there) - I decided to ask the real php coders. Is there a better, more efficient way to write the code?


I'd recommend caching - generating the HTML mark-up and storing that in a cache, and using that rather then generating the list on each page load.

Of course, the cache would have to cleared if a recipe is ever added, removed or changes title.

add_shortcode('recipe_list', 'recipe_query');
function recipe_query( $atts, $content ){

     //Get mark-up from cache (if present)
     $html = get_transient( 'wpse123038_recipe_list' );

     if( !$html ){
          //Nothing in cache - generate mark-up
          $html = '';

          //Store in cache (for a long time - a year?)
          set_transient( 'wpse123038_recipe_list', $html, 60*60*24*365 );     

     return $html;

Now everytime we add/remove a post (or may be its published and then we set it to 'draft') - basically anytime it might go from not being in the list, to being on the list :). (Note, you'll also want to clear the cache whenever the recipe title changes...)

function wpse123038_recipe_status_changes( $new_status, $old_status, $post ) {

    //Check if status has changed
    if( $new_status == $old_status ){

    //Check post type
    if( 'recipes' != get_post_type( $post) ){

    //Check if we're publishing on 'unpublishing' it.
    if( 'publish' == $new_status || 'publish' == $old_status ){
         delete_transient( 'wpse123038_recipe_list' );

         //For bonus points, regenerate the cache here :)

add_action( 'transition_post_status', 'wpse123038_recipe_status_changes', 10, 3 );

So when ever a recipe is published, or is 'unpublished' the cache is cleared. This means the next visitor will have to wait for the mark-up to be generated again.

Of course, we're usually less concerned about page load times admin-side, so when the cache is cleared, you could regenerate it then. Giving a (usually) seamless experience on the front-end.

  • So, I understand what you're saying, but how do I integrate the code that generates the listing and the cache code? Do I remove the shortcode from the function that creates the list and add your code with the shortcode? – Louise Nov 12 '13 at 16:15
  • Your recipe_query() function currently generates the HTML mark-up, you want that inside teh //Nothing in cache - generate mark-up conditional. It generate the mark-up and assign it to $html. – Stephen Harris Nov 12 '13 at 18:03
  • Stephen, I've tried modifying the code and I get a white screen. Is there any chance, you'd give me the code combined into one to replace my original code? – Louise Nov 12 '13 at 19:20

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.