build_key( $key ); $data = get_transient( $full_key ); if ( false === $data ) { return false; } return $data; } /** * Set a value in the cache. * * @param string $key The cache key. * @param mixed $data The data to cache. * @param int $ttl Time-to-live in seconds. Defaults to 1 week. * @return bool True on success, false on failure. */ public function set( $key, $data, $ttl = 0 ) { if ( 0 === $ttl ) { $ttl = self::DEFAULT_TTL; } $full_key = $this->build_key( $key ); return set_transient( $full_key, $data, $ttl ); } /** * Delete a cached value by key. * * @param string $key The cache key. * @return bool True on success, false on failure. */ public function delete( $key ) { $full_key = $this->build_key( $key ); return delete_transient( $full_key ); } /** * Flush all Schema AI cache entries. * * Removes every transient whose option name begins with the plugin prefix. * * @return int Number of cache entries deleted. */ public function flush() { global $wpdb; $prefix = '_transient_' . self::CACHE_PREFIX; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Required for custom table; no WP API alternative exists. $results = $wpdb->get_col( $wpdb->prepare( 'SELECT option_name FROM ' . $wpdb->options . ' WHERE option_name LIKE %s', $wpdb->esc_like( $prefix ) . '%' ) ); $count = 0; foreach ( $results as $option_name ) { // Strip the '_transient_' prefix to get the transient name. $transient_name = str_replace( '_transient_', '', $option_name ); if ( delete_transient( $transient_name ) ) { $count++; } } return $count; } /** * Generate a cache key for a specific post based on its content. * * The key is built from the post ID and a hash of the post's title and * content so that the cache automatically invalidates when the post is * edited. * * @param int $post_id WordPress post ID. * @return string Cache key in the format {post_id}_{content_hash}. */ public function generate_post_key( $post_id ) { $content_hash = $this->generate_content_hash( $post_id ); return $post_id . '_' . $content_hash; } /** * Generate a content hash from the post title and content. * * @param int $post_id WordPress post ID. * @return string MD5 hash of the post title concatenated with its content. */ public function generate_content_hash( $post_id ) { $post = get_post( $post_id ); if ( ! $post ) { return md5( (string) $post_id ); } $raw = $post->post_title . $post->post_content; return md5( $raw ); } /** * Build the full transient key by prepending the cache prefix. * * WordPress limits transient names to 172 characters. If the resulting key * exceeds that length it is hashed to guarantee it fits. * * @param string $key Short cache key. * @return string Full transient key. */ private function build_key( $key ) { $full = self::CACHE_PREFIX . $key; // WordPress transient name limit is 172 chars. if ( strlen( $full ) > 172 ) { $full = self::CACHE_PREFIX . md5( $key ); } return $full; } }