1

In my index.php file, inside the classic WordPress loop, I had to query posts in order to retrieve the ones with a relationship value created with a custom field (managed with ACF plugin).

I managed to do it using the get_posts() function and a foreach loop. But, as I have 300 posts, it slows down the page load time.

So, in this perspective, I was looking for a way to reduce the amount of posts fetched by get_posts(), or the number of queries, using different parameters. But, it seems the parameters I'm using are increasing the number of queries.

This is the code I'm trying to improve :

    <?php
    $artists = get_posts(array(
      'post_type'           => 'post',
      'numberposts'         => '1',
      'meta_query'          => array(
            array(
              'key'       => 'relation', // name of custom field
                'value'   => '"' . get_the_ID() . '"', // matches exactly "123", not just 123. This prevents a match for "1234"
                'compare' => 'LIKE'
            )
      )
    ));

    ?>
    <?php if( $artists ) : ?>
      <?php foreach( $artists as $artist ) : ?>
        <p>
          <a href="<?php echo get_permalink( $artist->ID ); ?>"><?php echo get_the_title( $artist->ID ); ?></a>
        </p>
      <?php endforeach; ?>
    <?php endif; ?>

First of all, I'm using the paramater 'numberposts' => '1', instead of the default 'numberposts' => '5', in order to limit the number of posts and the query time, but i dont see any improvement, and if i use 'numberposts' => '-1' (which is not limiting the number of posts), the number of queries decrease and the load time as well. Why ?

Then, if i use this chunk of code instead of the previous one, the number of queries increase but the load time decrease :

<?php
    // trying to limit the number of posts targeting only the one with a specific relationship field
    $ids = get_field('relationship_field_name', false, false);

    $artists = get_posts(array(
      'post_type'           => 'post',
      'numberposts'         => '1',
      'post__in'            => $ids,
      )
    ));

    ?>
<?php if( $artists ) : ?>
  <?php foreach( $artists as $artist ) : ?>
    <p>
      <a href="<?php echo get_permalink( $artist->ID ); ?>"><?php echo get_the_title( $artist->ID ); ?></a>
    </p>
  <?php endforeach; ?>
<?php endif; ?>

EDIT :

The most efficient piece of code I've been able to produce is, with (according to Query Monitor plugin) only 616 queries and 0,4775s Database Query Time :

<?php
$ids = get_field('relation', false, false);

$artists = get_posts(array(
  'post_type'     => 'post',
  'numberposts'   => '-1',
  'post__in'      => $ids,
));

?>
<?php if( $artists ) : ?>
  <?php foreach( $artists as $artist ) : ?>
    <p>
      <a href="<?php echo get_permalink( $artist->ID ); ?>"><?php echo get_the_title( $artist->ID ); ?></a>
    </p>
  <?php endforeach; ?>
<?php endif; ?>

If I set the parameter 'numberposts' to 1, or if I let to its default value, I obtain 1069 Queries and 0,7291s Database Query Time.

What a Im missing with get_posts() ? How to optimize the efficiency of the code, decrease the number of queries and the load time ?

0

It's everything OK with get_posts() since it creates the single WP_Query instance per call. You can check the query by creating that instance:

<?php
$test_query = new WP_Query(
    array(
        'post_type'      => 'post',
        'posts_per_page' => -1, // any number, does not matter
        'post__in'       => $ids, // should be an array!
    )
);

echo $test_query->request;

Adding 'meta_query' or other parameters will (not necessarily) increase query complexity (and, therefore, query time), but will not increase the number of queries.

It's not enough information to find out why there are so many queries.

Adopted since OP's comment (later on):

See. Load time depends on the number of queries (first) and their complexity (second) (or, otherwise, or, both). I can't figure out why do you have so many queries when I don't see what happens inside your Loop, inside while. I think you do the same query inside the Loop for each of 300 posts. Don't do get_posts() inside the Loop. If you need some relations between posts, use taxonomies, they were designed for this purpose. Like tags or categories or custom movies, nappers, wooden toys, bicycles, etc. Do you see belonging on to another? Querieng custop fields was one of the most resource-eating things in WordPress. Use Taxonomies where queries are adopted to frequent use. Rethink the architecture excluding that plugin and come up with a new idea.

  • If I understand, the number of queries isn't necessarily the cause of the load time, but the complexity of the query sometimes (especially when there is a meta_query). I've checked the query, but I'm still not advanced enough to understand how to improve it from a performance perspective. I assume if I reduce the number of posts affected by the query with more precise parameters, the load time will decrease. I could for example create a CPT, move the posts in this CPT and then filter them with the post_type parameter. This could reduce the query time. – PhpDoe Jan 9 at 17:10
  • Thanks a lot. The only thing I can't figure out is how to create relationship between 150 posts "books" to 150 posts "author" using taxonomies, except creating a tag for each author. But I will dig into this. Using get_posts() inside the loop is definitively not a got idea :) ! Thanks again. – PhpDoe Jan 10 at 10:29
  • Register a number of taxonomies, as you say 'books' and 'author', and go with them. Forget about get_posts() but ask WP_Query to return only posts where 'books' and 'author' belong to. – Max Yudin Jan 11 at 12:40
  • Thanks to your comments, I feel I'm on the right way coding it. Thanks a lot ! – PhpDoe Jan 13 at 18:22

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.