LLMS_Comments
Custom filters & actions for LifterLMS comments.
Description Description
This class owes a great debt to WooCommerce.
Source Source
File: includes/class.llms.comments.php
class LLMS_Comments { /** * Transient key where calculated comment stats are stored. * * @var string */ protected static $count_transient_key = 'llms_count_comments'; /** * Constructor. * * @since 3.37.12 * @since 6.6.0 Conditionally hook `wp_count_comments` filter. * * @return void */ public function __construct() { // Secure order notes. add_filter( 'comments_clauses', array( __CLASS__, 'exclude_order_comments' ), 10, 1 ); add_action( 'comment_feed_join', array( __CLASS__, 'exclude_order_comments_from_feed_join' ) ); add_action( 'comment_feed_where', array( __CLASS__, 'exclude_order_comments_from_feed_where' ) ); // Delete comments count cache whenever there is a new comment or a comment status changes. add_action( 'wp_insert_comment', array( __CLASS__, 'delete_comments_count_cache' ) ); add_action( 'wp_set_comment_status', array( __CLASS__, 'delete_comments_count_cache' ) ); /** * Remove order notes when counting comments on WP versions earlier than 6.0. * * @todo This filter can be safely deprecated once support is dropped for WordPress 6.0. */ if ( self::should_modify_comment_counts() ) { add_filter( 'wp_count_comments', array( __CLASS__, 'wp_count_comments' ), 999, 2 ); } } /** * Delete transient data when inserting new comments or updating comment status * * Next time wp_count_comments is called it'll be automatically regenerated * * @since 3.0.0 * @since 3.37.12 Use class variable to access the transient key name. * * @return void */ public static function delete_comments_count_cache() { delete_transient( self::$count_transient_key ); } /** * Exclude order comments from queries and RSS. * * @since 3.0.0 * @since 3.37.12 Use strict comparison for `in_array()`. * * @param array $clauses Array of SQL clauses. * @return array */ public static function exclude_order_comments( $clauses ) { global $wpdb, $typenow; // Allow queries when in the admin. if ( is_admin() && in_array( $typenow, array( 'llms_order' ), true ) && current_user_can( apply_filters( 'lifterlms_admin_order_access', 'manage_options' ) ) ) { return $clauses; } if ( ! $clauses['join'] ) { $clauses['join'] = ''; } if ( ! strstr( $clauses['join'], "JOIN $wpdb->posts" ) ) { $clauses['join'] .= " LEFT JOIN $wpdb->posts ON comment_post_ID = $wpdb->posts.ID "; } if ( $clauses['where'] ) { $clauses['where'] .= ' AND '; } $clauses['where'] .= " $wpdb->posts.post_type NOT IN ('" . implode( "','", array( 'llms_order' ) ) . "') "; return $clauses; } /** * Exclude order comments from queries and RSS. * * @since 3.0.0 * * @param string $join SQL join clause. * @return string */ public static function exclude_order_comments_from_feed_join( $join ) { global $wpdb; if ( ! strstr( $join, $wpdb->posts ) ) { $join = " LEFT JOIN $wpdb->posts ON $wpdb->comments.comment_post_ID = $wpdb->posts.ID "; } return $join; } /** * Exclude order comments from queries and RSS. * * @since 3.0.0 * * @param string $where SQL where clause. * @return string */ public static function exclude_order_comments_from_feed_where( $where ) { global $wpdb; if ( $where ) { $where .= ' AND '; } $where .= " $wpdb->posts.post_type NOT IN ('" . implode( "','", array( 'llms_order' ) ) . "') "; return $where; } /** * Retrieve an array mapping database values to their human-readable meanings * * The array key is the value stored in the $wpdb->comments table for the `comment_approved` column. * * The array values are the equivalent value as expected by the return of the `wp_count_comments()` function. * * @since 3.37.12 * * @return array */ protected static function get_approved_map() { return array( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed', ); } /** * Retrieve order note comment counts. * * @since 3.37.12 * * @return array[] */ protected static function get_note_counts() { global $wpdb; return $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching " SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type = 'llms_order_note' GROUP BY comment_approved; ", ARRAY_A ); } /** * Remove order notes from an existing comment count stats object. * * This method accepts a stats object, generated by another plugin (like WooCommerce) or using core information * from `get_comment_counts()` and then subtracts LifterLMS order note comments from the existing comment counts * which would have included order notes in the counts. * * @since 3.37.12 * * @todo This method can be safely deprecated once support is dropped for WordPress 6.0. * * @param stdClass $stats Comment stats object. See the return of LLMS_Comments::wp_comment_counts() for object details. * @return stdClass See LLMS_Comments::wp_comment_counts() for return object details. */ protected static function modify_comment_stats( $stats ) { $counts = self::get_note_counts(); $map = self::get_approved_map(); foreach ( (array) $counts as $row ) { if ( ! in_array( $row['comment_approved'], array( 'post-trashed', 'trash', 'spam' ), true ) ) { $stats->all -= $row['num_comments']; $stats->total_comments -= $row['num_comments']; } if ( isset( $map[ $row['comment_approved'] ] ) ) { $var = $map[ $row['comment_approved'] ]; $stats->$var -= $row['num_comments']; } } set_transient( self::$count_transient_key, $stats ); return $stats; } /** * Determines whether or not comment count modification is necessary. * * Since WordPress 6.0 the `get_comment_count()` function utilizes `get_comments()` whereas in earlier versions the counts * are retrieved by a direct SQL query. This change means that the filter in this class on `comments_clauses` ensures that * our comments we hide & don't count in the comments management UI are already excluded and we do not need to filter * `wp_count_comments` to subtract our comments. * * @since 6.6.0 * * @return boolean Returns `true` on WP earlier than 6.0 and `false` on 6.0 and later. */ private static function should_modify_comment_counts() { global $wp_version; return version_compare( $wp_version, '6.0-src', '<' ); } /** * Remove order notes from the count when counting comments * * This method is hooked to `wp_count_comments`, called by `wp_count_comments()`. * * It handles two potential scenarios: * * 1) No other plugins have run the filter and the incoming $stats is an empty array. * In this scenario we'll utilize `get_comment_count()` to create a new $stats object * * 2) Another plugin has already generated a stats object and then incoming $stats is a stdClass. * * In either scenario we query the number of order notes and subtract this number from the existing * comment counts. * * @since 3.0.0 * @since 3.37.12 Use strict comparisons. * Fix issue encountered when $stats is an empty array. * Modify the stats generation method. * @since 6.6.0 Will throw `_doing_it_wrong()` when run on WP 6.0 or later and return the input `$stats` unchanged. * * @todo This method can be safely deprecated once support is dropped for WordPress 6.0. * * @param stdClass|array $stats Empty array or a stdClass of stats from another plugin. * @param int $post_id WP Post ID. `0` indicates comment stats for the entire site. * @return stdClass { * The number of comments keyed by their status. * * @type int $approved The number of approved comments. * @type int $moderated The number of comments awaiting moderation (a.k.a. pending). * @type int $spam The number of spam comments. * @type int $trash The number of trashed comments. * @type int $post-trashed The number of comments for posts that are in the trash. * @type int $total_comments The total number of non-trashed comments, including spam. * @type int $all The total number of pending or approved comments. * } */ public static function wp_count_comments( $stats, $post_id ) { // If someone calls this directly on 6.0 or later notify them and return early. if ( ! self::should_modify_comment_counts() ) { _doing_it_wrong( __METHOD__, 'This method should not be called on WordPress 6.0 or later.', '6.6.0' ); return $stats; } // Don't modify when querying for a specific post. if ( 0 !== $post_id ) { return $stats; } // Return cached object if available. $cached = get_transient( self::$count_transient_key ); if ( $cached ) { return $cached; } // If $stats is empty, get a new object from the WP Core that we can modify. if ( empty( $stats ) ) { $stats = get_comment_count( $post_id ); // The keys in wp_count_comments() and get_comment_counts() don't match. $stats['moderated'] = $stats['awaiting_moderation']; unset( $stats['awaiting_moderation'] ); // Cast to an object. $stats = (object) $stats; } // Otherwise modify the existing stats object. return self::modify_comment_stats( $stats ); } }
Expand full source code Collapse full source code View on GitHub
Methods Methods
- __construct — Constructor.
- delete_comments_count_cache — Delete transient data when inserting new comments or updating comment status
- exclude_order_comments — Exclude order comments from queries and RSS.
- exclude_order_comments_from_feed_join — Exclude order comments from queries and RSS.
- exclude_order_comments_from_feed_where — Exclude order comments from queries and RSS.
- get_approved_map — Retrieve an array mapping database values to their human-readable meanings
- get_note_counts — Retrieve order note comment counts.
- modify_comment_stats — Remove order notes from an existing comment count stats object.
- should_modify_comment_counts — Determines whether or not comment count modification is necessary.
- wp_count_comments — Remove order notes from the count when counting comments
Changelog Changelog
Version | Description |
---|---|
3.0.0 | Introduced. |