query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key LIKE %s", $post_id, $wpdb->esc_like( self::META_PREFIX ) . '%' ) ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching wp_cache_delete( $post_id, 'post_meta' ); } /** * Purge every cached list in the database. */ public static function purge_database() { global $wpdb; // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Bulk meta delete by key pattern has no core API; the object cache is flushed right after. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE %s", $wpdb->esc_like( self::META_PREFIX ) . '%' ) ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching wp_cache_flush(); self::flush_all(); } /** * Invalidate when a post is saved. * * @param int $post_id Post ID. * @param WP_Post $post Post object. */ public static function on_save_post( $post_id, $post ) { if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) { return; } if ( SRPP_CPT === $post->post_type ) { self::flush_all(); return; } self::flush_post( $post_id ); } /** * Terms changed — relatedness for other posts may change too. * * @param int $object_id Object ID. * @param array $terms Terms. * @param array $tt_ids Term taxonomy IDs. * @param string $taxonomy Taxonomy. */ public static function on_set_terms( $object_id, $terms, $tt_ids, $taxonomy ) { unset( $terms, $tt_ids ); $tax = get_taxonomy( $taxonomy ); if ( ! $tax || ! $tax->public ) { return; } self::flush_post( $object_id ); self::flush_all(); } /** * Publish/unpublish changes candidate pools. * * @param string $new New status. * @param string $old Old status. * @param WP_Post $post Post. */ public static function on_transition( $new, $old, $post ) { if ( $new === $old || SRPP_CPT === $post->post_type ) { return; } if ( 'publish' === $new || 'publish' === $old ) { self::flush_all(); } } /** * Signature of a Display's relevant configuration. * * @param SRPP_Display $display Display. * @return string */ public static function signature( $display ) { $relevant = array( $display->opt( 'target_types' ), $display->opt( 'selection_mode' ), $display->opt( 'manual_ids' ), $display->opt( 'relate_by' ), $display->opt( 'engine' ), $display->opt( 'weights' ), $display->opt( 'recency_days' ), $display->opt( 'fallback' ), $display->opt( 'cross_match' ), $display->opt( 'order' ), $display->opt( 'items' ), $display->opt( 'ex_current' ), $display->opt( 'ex_password' ), $display->opt( 'ex_private' ), $display->opt( 'ex_noindex' ), $display->opt( 'ex_outofstock' ), $display->opt( 'ex_terms' ), $display->opt( 'ex_authors' ), $display->opt( 'ex_ids' ), ); return substr( md5( wp_json_encode( $relevant ) ), 0, 12 ); } /** * Read a cached ID list. * * @param SRPP_Display $display Display. * @param int $source_id Source post ID. * @return array|false */ public static function get( $display, $source_id ) { if ( ! srpp_get_option( 'cache_enabled', 1 ) ) { return false; } $ttl = (int) $display->opt( 'cache_ttl', DAY_IN_SECONDS ); if ( $ttl <= 0 ) { return false; } $entry = get_post_meta( $source_id, self::META_PREFIX . $display->id, true ); if ( ! is_array( $entry ) || ! isset( $entry['ids'], $entry['h'], $entry['t'], $entry['v'] ) ) { return false; } if ( (int) $entry['v'] !== self::version() ) { return false; } if ( $entry['h'] !== self::signature( $display ) ) { return false; } if ( ( time() - (int) $entry['t'] ) > $ttl ) { return false; } return array_map( 'absint', (array) $entry['ids'] ); } /** * Store an ID list. * * @param SRPP_Display $display Display. * @param int $source_id Source post ID. * @param array $ids Resolved IDs. */ public static function set( $display, $source_id, $ids ) { if ( ! srpp_get_option( 'cache_enabled', 1 ) || (int) $display->opt( 'cache_ttl' ) <= 0 ) { return; } update_post_meta( $source_id, self::META_PREFIX . $display->id, array( 'v' => self::version(), 'h' => self::signature( $display ), 't' => time(), 'ids' => array_map( 'absint', $ids ), ) ); } /** * How many cached rows exist (for the Tools screen). * * @return int */ public static function count_rows() { global $wpdb; $key = 'srpp_cached_rows'; $count = wp_cache_get( $key, 'srpp' ); if ( false !== $count ) { return (int) $count; } // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Counting meta by key pattern has no core API; the result is cached below. $count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_key LIKE %s", $wpdb->esc_like( self::META_PREFIX ) . '%' ) ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching wp_cache_set( $key, $count, 'srpp', 5 * MINUTE_IN_SECONDS ); return $count; } }