Skip to content

Instantly share code, notes, and snippets.

@mklepaczewski
Created December 16, 2021 13:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mklepaczewski/51817ee3d43f792a475f68fee154d723 to your computer and use it in GitHub Desktop.
Save mklepaczewski/51817ee3d43f792a475f68fee154d723 to your computer and use it in GitHub Desktop.
Patch for wpDiscuz bug where persistent cache is being used and 'Load more comments' button loads the same comments
<?php
/*
Plugin Name: FasterWebsite wpDiscuz Cache Patch
Plugin URI: https://fasterwebsite.com/
Description: Fixes bug 'Load More button loads the same comments'
Author: Maciej Klepaczewski
Author URI: https://fasterwebsite.com/
Version: 0.1
Requires PHP: 7.4
*/
/**
* @author Maciej Klepaczewski <matt@fasterwebsite.com>
* @link https://fasterwebsite.com/
* @copyright Copyright (c) 2021, Maciej Klepaczewski FasterWebsite.com
*/
declare(strict_types=1);
namespace fasterwebsite\wpdiscuz\patch1;
use WP_Comment_Query;
/**
*
* Patch for bug where when persistent caching is enabled wpDiscuz will fail to load next batch of comments when
* 'Load More Comments' button is clicked.
*
* Why it happens:
* The problem is in caching done by WP_Comment_Query::get_comments(). The method generates cache key based only on
* WP_Comment_Query::query_var_defaults, which does not hold some keys that are being injected into SQL query to fetch
* comments by wpDiscuz WpdiscuzCore::commentsClauses() (which hooks into 'comments_clauses' hook fired by
* WP_Comment_Query::get_comment_ids()). The result is that two requests with different "lastParentId" parameters have the
* same cache key. When persistent cache is enabled (Redis, Memcached etc.) this results in retrieving incorrect comments
* for the request.
*
* Solution:
* WP_Comment_Query::get_comments() uses WP_Comment_Query::query_vars to generate the cache key
* WP_Comment_Query::get_comments() considers only those parameters in WP_Comment_Query::query_vars that are defined
* in WP_Comment_Query::default_query_vars. So, the solution is:
* - hook into 'comments_pre_query' and inject into WP_Comment_Query::default_query_vars our custom variables so they
* are being taken into account while generating cache key. Also, inject actual values into WP_Comment_Query::query_vars
* - let WP_Comment_Query generate the cache key
* - remove our changes after cache key has been generated, as soon as possible. This happens by hooking into the
* 'the_comments' hook and removing our changes from both WP_Comment_Query::default_query_vars and WP_Comment_Query::query_vars
*
* Note that wpDiscuz injects some variables into WP_Comment_Query::query_vars and we could add these using
* WP_Comment_Query::default_query_vars, but it seems to be more intrusive and requires more knowledge.
*/
class Patch {
public function __construct() {
if(!$this->isApplicableToRequest()) {
return;
}
/* This will inject our custom variable into WP_Comment_Query::query_var_defaults and query_vars */
add_filter('comments_pre_query', function($comment_data, WP_Comment_Query $query) {
$query->query_var_defaults['wpdiscuz'] = 'temporary_from_' . __CLASS__ . "::" . __METHOD__;
$this->addWpDiscuzParams($query);
/* Don't change $comment_data */
return $comment_data;
}, PHP_INT_MAX, 2);
/* This will remove it */
add_filter('the_comments', function($_comments, WP_Comment_Query $query) {
unset($query->query_var_defaults['wpdiscuz']);
return $_comments;
}, PHP_INT_MIN, 2);
}
/**
* Decides if this patch should actually run.
*
* We run it
* @return bool
*/
public function isApplicableToRequest() : bool {
if(!wp_doing_ajax()) {
return false;
}
if(!isset($_REQUEST['action']) || $_REQUEST['action'] !== 'wpdLoadMoreComments') {
return false;
}
return true;
}
private function addWpDiscuzParams(WP_Comment_Query $query) : void {
$query->query_vars['wpdiscuz'] = wp_array_slice_assoc($_REQUEST, $this->getWpDiscuzSpecificArgs());
}
/**
* @return array<string>
*/
private function getWpDiscuzSpecificArgs() : array {
return ['lastParentId', 'isFirstLoad', "offset", "sorting"];
}
}
new Patch();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment