How to speed up a wordpress function with multiple loops?

enter image description here

I am a PHP novice and wrote this function. It is an alphabetical navigation which shows only the letter that have posts in both that letter and the currently filtered “genero” taxonomy term.

Read More

I use multiple taxonomy queries to find “artistas” posts that, for example, are tagged as both “rock” and “funk”.

The function works perfectly and outputs exactly what I want it to, but…

The multiple loops are really lagging the load time and, being the n00b that I am, am uncertain of how to optimize the function.

Any pointers or guidance would be VERY much appreciated. If you want I can trade time for time (i write some mean CSS) 🙂

thank you!

<?php
    function bam_artist_alfa() {
            $taxonomy = 'alfa';  
            $uri = my_url();
            $home = 'http://buenosairesmusic.com/';

            // save the terms that have posts in an array as a transient
            if ( false === ( $alphabet = get_transient( 'bam_archive_alphabet' ) ) ) {
                // It wasn't there, so regenerate the data and save the transient
                $terms = get_terms($taxonomy);

                $alphabet = array();
                if($terms){
                    foreach ($terms as $term){
                        $alphabet[] = $term->slug;
                    }
                }
                set_transient( 'bam_archive_alphabet', $alphabet );
            } 

            if(strstr($uri, '/artista/') ) {
                $uri = str_replace('/artista/','/?alfa=', $uri);
                $uri = substr_replace($uri ,"",-1);
            }

            $all_link = removeqsvar($uri, 'alfa');
            $last = $all_link[strlen($all_link)-1]; 

            if($last == '?') $all_link = substr_replace($all_link ,"",-1);

            if($all_link == $home) 
                $all_link = $home.'artistas';

            if( isset($_GET) && isset($_GET['alfa']) ) {
                $is_alfa = (!is_tax('alfa') && !$_GET['alfa'] ? false : true );
            } else {
                $is_alfa = (!is_tax('alfa') ? false : true );
            }

            $all_current = ($is_alfa == true ? null : ' bg1 round-res' );


        ?>

                    <ul class="bbw bo alfa-nav c2">
                        <li class="all-link<?php echo $all_current; ?>">
                        <?php if(!$is_alfa) { echo 'A&ndash;Z'; } else { ?>

                            <a href="<?php echo $all_link; ?>">A&ndash;Z</a>
                        <?php }?>

                        </li>
    <?php
        $query = $_SERVER['QUERY_STRING'];
        $genre = null;
        $orden = (isset($_GET) && isset($_GET['orden']) ? '&orden=fecha' : null);

        if( strstr($uri,'/genero/') ) {
            $genre = str_replace('/genero/','/?genero=', $uri);
            $genre = substr_replace($uri ,"",-1);
            $genre = explode('/',$genre);
            $genre = end($genre);
        } elseif( isset($_GET) && isset($_GET['genero']) ) {
            $genre = $_GET['genero'];
        }

        if(!empty($genre)) {
            $spaces = strpos($genre,' ');
            $genre = ($spaces === false ? $genre : explode(' ', $genre) );
        }

        function has_artists($i, $genre) {

            if(empty($genre)) {
                $termquery['tax_query'] = array(
                    array(
                        'taxonomy' => 'alfa',
                        'terms' => $i,
                        'field' => 'slug',
                    ),
                );

                $termquery['post_type'] = 'artistas';
            } else {
                $alfaquery[] = array(
                    'taxonomy' => 'alfa',
                    'terms' => $i,
                    'field' => 'slug',
                );

                if(is_array($genre)) {
                    $genres[] = array(
                        'taxonomy' => 'genero',
                        'terms' => $genre,
                        'field' => 'slug',
                        'operator' => 'AND'
                    );      
                } else {
                    $genres[] = array(
                        'taxonomy' => 'genero',
                        'terms' => $genre,
                        'field' => 'slug',      
                    );
                }
                $termquery['tax_query'] = array_merge($genres, $alfaquery);
                $termquery['tax_query']['relation'] = "AND";
                $termquery['post_type'] = 'artistas';
            }

            $has_artists = get_posts($termquery);

            if($has_artists) {
                return true;
            } else {
                return false;
            }
        }

        foreach(range('a', 'z') as $i) : 

            $current = ($i == get_query_var($taxonomy)) ? "bg1 round-res" : "menu-item";

            if(empty($genre)) {
                $link = $home.'?alfa='.$i.$orden;
            } else {
                $genrestring = (is_array($genre) ? implode('+',$genre) : $genrestring = $genre );
                $link = $home.'?alfa='.$i.'&genero='.$genrestring.$orden;
            }

            if ( has_artists($i,$genre) && $i != get_query_var($taxonomy) ){ 
    ?>

                        <li class="<?php echo $current; ?>">
                            <?php printf('<a href="%s">%s</a>', $link, strtoupper($i) ) ?>
                        </li>
        <?php } else { ?>

                        <li class="<?php echo $current;  if($i != get_query_var($taxonomy)) {echo ' empty';} ?>">
                            <?php echo strtoupper($i); ?>
                        </li>
        <?php 
            }
            endforeach;
        ?>

                     </ul>
    <?php } ?>

Related posts

Leave a Reply

2 comments

  1. I would just retrieve an array of alphabet/taxonomy terms that have posts. You do this, but doesn’t actually use it. This function will return an array of non-empty (alphabet) terms:

    (Transient? – unless you have multiple post types using this taxonomy, (see below) I’m not sure if much is gained from using transients – and you can just call to get_terms and use wp_list_pluck as shown). The following function uses transients.

     wpse50148_get_used_alpha(){
    
         if ( false === ( $alphabet = get_transient( 'bam_archive_alphabet' ) ) ) {
                //It wasn't there, so regenerate the data and save the transient
                $terms = get_terms('alfa');
                $alphabet =array();
                if($terms){
                    $alphabet = wp_list_pluck($terms,'slug');
                }
                set_transient( 'bam_archive_alphabet', $alphabet );
            } 
    
          return $alphabet;
     }
    

    Don’t forget to update the transient when a post is updated.

    This method assumes that the only post type using this taxonomy is ‘artistas’ – if it is being shared then a letter may claim to have artistas associated with it (in your menu) when it does not.

    Shared taxonomy work-around

    To get round this, you would have to query the posts and then loop through them and collect their terms. Either way – only 1, not 26 queries are being performed to get the ‘used’ alphabet. A transient would be more obviously time-saving in this scenario.

    Usage:

      $alphabet = wpse50148_get_used_alpha();
    
       foreach(range('a', 'z') as $i) : 
          if( in_array($i,$alphabet) ){
               //Letter has terms
          }else{
               //Letter does not have terms
          }
       endif;
    
  2. I didn’t use the transients API yet but in this case I think it’s a good choice. You use it but only for a small part of the data.

    To cache artists per alfa and genre you could do something like this (I assume):

    if ( false === ( $has_artists = get_transient( "bam_artist_$i_$genre" ) ) ) {
        $has_artists = get_posts($termquery);
        set_transient( "bam_artist_$i_$genre", $has_artists );
    }