web-dev-qa-db-fra.com

Effacement des données du plug-in mis en cache s'il utilise un cache d'objets externe

J'ai créé un plug-in qui met en cache certaines des données qu'il utilise - principalement les résultats des appels d'API Salesforce REST API, et les expire à intervalles réguliers (par défaut toutes les 24 heures).

Le plugin appelle ces méthodes pour contrôler la mise en cache:

/**
 * Check to see if this API call exists in the cache
 * if it does, return the transient for that key
 *
 * @param string $url The API call we'd like to make.
 * @param array  $args The arguents of the API call.
 * @return get_transient $cachekey
 */
public function cache_get( $url, $args ) {
    if ( is_array( $args ) ) {
        $args[] = $url;
        array_multisort( $args );
    } else {
        $args .= $url;
    }
    $prefix = esc_sql( $this->transient_prefix() );
    $cachekey = $prefix . md5( wp_json_encode( $args ) );
    return get_transient( $cachekey );
}

/**
 * Create a cache entry for the current result, with the url and args as the key
 *
 * @param string $url The API query URL.
 * @param array  $args The arguments passed on the API query.
 * @param array  $data The data received.
 * @param string $cache_expiration How long to keep the cache result around for.
 * @return Bool whether or not the value was set
 * @link https://developer.wordpress.org/reference/functions/set_transient/
 */
public function cache_set( $url, $args, $data, $cache_expiration = '' ) {
    if ( is_array( $args ) ) {
        $args[] = $url;
        array_multisort( $args );
    } else {
        $args .= $url;
    }
    $prefix = esc_sql( $this->transient_prefix() );
    $cachekey = $prefix . md5( wp_json_encode( $args ) );
    // Cache_expiration is how long it should be stored in the cache.
    // If we didn't give a custom one, use the default.
    if ( '' === $cache_expiration ) {
        $cache_expiration = $this->options['cache_expiration'];
    }
    return set_transient( $cachekey, $data, $cache_expiration );
}

/**
 * Get the cache transient prefix for this plugin and return it
 *
 * @return The transient prefix
 */
private function transient_prefix() {
    $transient_prefix = 'sfwp';
    return $transient_prefix;
}

/**
 * If there is a WordPress setting for how long to keep this specific cache, return it and set the object property
 * Otherwise, return seconds in 24 hours
 *
 * @param string $option_key The cache item to keep around.
 * @param int    $expire The default time after which to expire the cache.
 * @return The cache expiration saved in the database.
 */
public function cache_expiration( $option_key, $expire ) {
    $cache_expiration = get_option( $option_key, $expire );
    return $cache_expiration;
}

J'aimerais cependant fournir aux utilisateurs un moyen d'effacer ce cache manuellement, dans l'éventualité où ils modifieraient la configuration de leurs objets Salesforce et ne voudraient pas attendre l'expiration automatique. Je voudrais cependant éviter de vider le cache du site entier (ceci est ma compréhension de ce que ferait wp_cache_flush()).

Je viens d'ajouter le $transient_prefix dans les méthodes ci-dessus, car je réalise que ce serait facile si le site n'utilisait que l'API Transients. Mais s'ils utilisent un cache d'objets, je suis hors de ma ligue.

J'ai créé une méthode cache_purge comme celle-ci:

/**
 * Create a cache entry for the current result, with the url and args as the key
 *
 * @param string $subset If we only want to purge WordPress data, Salesforce data, options, etc.
 * @return Bool whether or not the purge was successful
 */
public function cache_purge( $subset = '' ) {
    $prefix = esc_sql( $this->transient_prefix() );

    // cache is stored somewhere other than the options table
    if ( wp_using_ext_object_cache() ) {

    } else {
        // cache is stored in the options table. this is pretty easy.
        $options = $this->wpdb->options;
        $t = esc_sql( '_transient_timeout_' . $prefix . '%' );
        $sql = $wpdb ->prepare( "SELECT option_name FROM $options WHERE option_name LIKE '%s'", $t );
        $transients = $this->wpdb->get_col( $sql );
        foreach ( $transients as $transient ) {
            // Strip away the WordPress prefix in order to arrive at the transient key.
            $key = str_replace( '_transient_timeout_', '', $transient );
            // Now that we have the key, use WordPress core to the delete the transient.
            delete_transient( $key );
        }
    }
}

D'après ce que je comprends, cela me permettrait de vérifier l'existence de tout cache d'objets externe (qui couvrirait, selon moi, les plugins de mise en cache, ainsi que Varnish/memcache/etc.). S'il n'y en a pas, effacez l'API transitoires.

Est-ce que j'ai raison jusqu'à présent? Si tel est le cas, que puis-je faire pour effacer les mêmes données d'un cache d'objets?

1
Jonathan Stegall

Nous notons que l'API transitoires utilise l'API de cache d'objets lorsque nous utilisons un fichier à insertion rapide object-cache.php.

Par exemple, si wp_using_ext_object_cache() renvoie true, alors

get_transient( $transient ) 
-> wp_cache_get( $transient, 'transient' )

set_transient( $transient, $value, $expiration ) 
-> wp_cache_set( $transient, $value, 'transient', $expiration )

delete_transient( $transient ) 
-> wp_cache_delete( $transient, 'transient' )

où le groupe est transient.

L’API de cache d’objets ne prend pas en charge la fonction wp_cache_delete_group() pour supprimer le cache par un groupe et elle dispose actuellement d’un wontfix dans le ticket # 4476 .

La raison invoquée était que toutes les solutions de cache persistant ne la prenaient pas en charge. Mais il existe certaines manières décrites dans le ticket, qui dépendent de la solution de cache.

Par exemple, l’implémentation du cache d’objets persistants de WP Redis prend en charge wp_cache_delete_group(), mais pas le cache d’objets Memcached implémentation.

Si nous utilisons des transitoires dans notre plugin, avec le cache d'objets persistant, alors nous devrions noter que si nous avons utilisé:

if( function_exists( 'wp_cache_delete_group' ) )
{
    wp_cache_delete_group( 'transient' );
}

il semble alors que nous viderions tous les transitoires, pas seulement ceux définis dans notre propre plugin.

Si les clés de cache sont connues à l'avance, nous pourrions les supprimer avec:

wp_cache_delete( $cachekey, $cachegroup );

$cachegroup est 'transient' si nous avons utilisé des transitoires.

1
birgire