Make WordPress Core

Opened 13 months ago

Last modified 12 months ago

#59702 new defect (bug)

Excerpt filters does not work in Ajax calls

Reported by: villamzr's profile villamzr Owned by:
Milestone: Awaiting Review Priority: normal
Severity: critical Version: 6.3.2
Component: Themes Keywords: changes-requested reporter-feedback
Focuses: template, coding-standards Cc:

Description

I'm creating a new WordPress theme, and using filters to format excerpts in Ajax calls, I found when the page loads at the first time, it works correctly, but, when I use the Ajax call to load posts progressively, the "the_excerpt()" method does not apply the filters to the excerpts.

I'm implementing the lazy load method for the posts, and I'm using the following three files for that propose.

functions.php

<?php
function custom_excerpt_length($length) {
    return 25;
}

function custom_excerpt_more($more) {
    return '...';
}

function load_more_posts() {
    $offset = $_POST["offset"];
    $limit = 5;

    $args = array(
        'post_type' => 'post',
        'posts_per_page' => $limit,
        'offset' => $offset
    );

    $query = new WP_Query($args);

    if($query->have_posts()) :
        while($query->have_posts()) :
            $query->the_post();
            get_template_part('content', get_post_format());
        endwhile;
    endif;
    
    wp_die();
}

add_filter( 'excerpt_length', 'custom_excerpt_length', 9999 );
add_filter('excerpt_more', 'custom_excerpt_more', 25);
add_action('wp_ajax_load_more_posts', 'load_more_posts');
add_action('wp_ajax_nopriv_load_more_posts', 'load_more_posts');

content.php

<?php
<div class="post-card">
    <?php if ( has_post_thumbnail() ): ?>
        <div class="post-image">
            <?php the_post_thumbnail('medium', array('loading' => 'lazy')); ?>
        </div>
    <?php endif; ?>
    <div class="post-content">
        <div class="post-title">
            <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
        </div>
        <div class="author-info">
            <?php echo get_avatar( get_the_author_meta( 'ID' ), 40 );?>
            <a href="<?php echo get_author_posts_url(get_the_author_meta('ID')); ?>" title="<?php the_author(); ?>">
                <span class="author-name"><?php the_author(); ?></span>
            </a>
            <a href="<?php echo get_day_link(get_the_time('Y'), get_the_time('m'), get_the_time('d')); ?>">
                <i class="fas fa-calendar"></i>
                <span class="post-date"><?php the_date(); ?></span>
            </a>
        </div>
        <div class="post-excerpt">
            <?php the_excerpt(); ?>
        </div>
        <div class="post-tags">
            <?php
                $tags = get_the_tags();
                if ($tags):
                    foreach($tags as $tag):
            ?>
                    <a href="<?php echo get_tag_link($tag->term_id); ?>" class="tags tags-<?php echo $tag->slug; ?>">
                        <?php echo $tag->name; ?>
                    </a>
            <?php
                    endforeach;
                endif;
            ?>
        </div>
    </div>
</div>

main.js

jQuery(document).ready(function($) {
  let offset = 5;
  let limit = 5;

  $(window).scroll(function() {
      if ($(window).scrollTop() + $(window).height() >= $('#load-more-posts').offset().top) {
          $.ajax({
              url: villamzr_localize.ajax_url,
              type: 'POST',
              data: {
                  action: 'load_more_posts',
                  offset: offset,
              },
              success: function(data) {
                  if (data) {
                    let $data = $(data);
                      $data.find('.post-excerpt p').each(function() {
                          let text = $(this).text();
                          $(this).text(text.substr(0, 150));
                      });
                      $('#post-container').append(data);
                  } else {
                      $('#load-more-posts').remove();
                  }
              }
          });
          offset += limit;     
      }
  });
});

Those are the files that I'm using to implement that. The code is correct and normal, but researching I found that the problem is the post-excerpt.php file, belonging to the WordPress core, it has an error in the logic in the following part:

post-excerpt.php

/** ... 
other code
*/

<?php
if ( is_admin() ||
        defined( 'REST_REQUEST' ) && REST_REQUEST ) {
        add_filter(
                'excerpt_length',
                static function() {
                        return 100;
                },
                PHP_INT_MAX
        );
}

For the filters to be applied to the Excerpt, the logic must be with && and not with ||. It is already tested and works. That is:

<?php
if ( is_admin() &&
        defined( 'REST_REQUEST' ) && REST_REQUEST ) {
        add_filter(
                'excerpt_length',
                static function() {
                        return 100;
                },
                PHP_INT_MAX
        );

Change History (2)

#1 @swissspidy
13 months ago

Hi there and welcome to WordPress Trac

We're already trac(k)ing this issue in #59043 with a pull request on the Gutenberg repo being worked on at https://github.com/WordPress/gutenberg/pull/55400. Looks like 6.4 is still the target for adding this fix.

#2 @rebelord
12 months ago

6.4.1 here and not fixed.
Here is a jQuery hotfix ex-post for anyone looking for it. To be used in

$.post( MyAjax.ajaxurl, formdata, function( response ){}


 /* hotfix for	excerpts length fail in Ajax - https://core.trac.wordpress.org/ticket/59702 */
	  let excerpts=$(response).find(".your_excerpt_parent_class p");
	  excerpts.each(function(){
		let excerpt=$(this).html();
		let new_excerpt = excerpt.split(" ").splice(0, 20).join(" "); /* 20 is the count of words needed */
		excerpt=excerpt.replace("“", "&#8220;"); /*these entities are present in the ajax output*/
		excerpt=excerpt.replace("”", "&#8221;");
		response=response.replace(excerpt, new_excerpt + " [...]");
	  });
Note: See TracTickets for help on using tickets.