私は WP Redis を使って $ wp_query オブジェクト全体を $ query_vars_hash とキャッシュしようとしています。
これが$wp_query
が$wp_object_cache
に追加された方法です。
add_action('wp', function($wp)
{
if ( is_admin() ) return;
global $wp_query;
if ( !wp_cache_get($wp_query->query_vars_hash, 'globals') )
{
wp_cache_add($wp_query->query_vars_hash, $wp_query, 'globals');
}
});
WP_Query
が投稿を取得する前に、クエリが既にキャッシュされているかどうかを確認する必要があります。
add_action('pre_get_posts', function($query)
{
if ( is_admin() ) return;
$cached_query = wp_cache_get($query->query_vars_hash, 'globals');
if ($cached_query)
{
$GLOBALS['wp_query'] = &$cached_query;
return; // Return immediately to prevent retrieving posts again.
}
});
問題 :
この場合、return
またはexit
は機能しません。それから、WP_Query
はまだ投稿を検索するためにデータベースにヒットします。
質問 :
プラグインに関係なく、投稿の取得をWP_Query
で完全に停止することは可能ですか?
現時点では、それは不可能です。
'pre_get_posts'
が実行されるとき、クエリを実行するためにWP_Query
を停止するには遅すぎます。
WordPress自体が、存在しない分類法を照会しようとすると、SQL照会のWHERE
節にAND (0 = 1)
を追加して、結果が非常に速く返されないようにします。
tracチケット はWP 4.6のコアとなると思われるパッチがあります。これは新しいフィルタを導入します:'posts_pre_query'
。そのフィルタに配列を返すと、WP_Query
は処理を停止し、提供された配列をposts配列として使用します。
これはどういうわけかあなたがやろうとしていることを実行するのにあなたを助けるかもしれません。
これを待って、あなたができることは何とかして ハッキング 、 トリック コア自体が同様にかなりハックなことです。
最近、私は トリック を使い始めて、きれいに止めることができないことをWordPressでやめたいと思っています。
例を示します。ここにあるすべてのコードは完全にテストされていないことに注意してください。
まず最初に、カスタム例外を書きましょう。
class My_StopWpQueryException extends Exception {
private $query;
public static forQuery(WP_Query $query) {
$instance = new static();
$instance->query = $query;
return $instance;
}
public function wpQuery() {
return $this->query;
}
}
この例外は、クエリオブジェクトを転送するための一種の _ dto _ として機能するように設計されているため、catch
ブロックで取得して使用できます。
より良いコードで説明してください:
function maybe_cached_query(WP_Query $query) {
$cached_query = wp_cache_get($query->query_vars_hash, 'globals');
if ($cached_query instanceof WP_Query)
throw My_StopWpQueryException::forQuery($cached_query);
}
function cached_query_set(WP_Query $query) {
$GLOBALS['wp_query'] = $query;
$GLOBALS['wp_the_query'] = $query;
// maybe some more fine-tuning here...
}
add_action('pre_get_posts', function(WP_Query $query) {
if ($query->is_main_query() && ! is_admin()) {
try {
maybe_cached_query($query);
} catch(My_StopWpQueryException $e) {
cached_query_set($e->wpQuery());
}
}
});
多かれ少なかれ動作するはずですが、起動しないフックがたくさんあります。例えば"the_posts"
など。これらのフックのいずれかを使ってトリガーするコードがあると、壊れることがあります。
テーマ/プラグインが必要とするかもしれないフックのいくつかを起動するためにcached_query_set
関数を使うことができます。
これはWordPressの質問よりもPHPの質問です。
As @Mark さんがコメントしました:
アクションから戻ってきても、呼び出し元の関数から魔法で戻ってきません
それは本当です。 return
をfunctionに入れることは関数を終了することを意味し、returnをPHP fileに置くことはファイルを終了することを意味します。 PHPコンストラクトexit()
:Pと混同しないでください(SO return
についてはPHPのほうが良い答えが見つかるかもしれません)。
そしてあなたの質問に答えるために
フルテーブルではなく単一のカラムを取得することで、クエリの負荷を軽減できます。 Like @birgire did here ホームページのクエリを削除する
まだ良い答えになるかもしれません。私はちょうど私が知っていることを共有しました:)
それは4.6でリリースされるまで変更されていないと仮定されます(posts_pre_query
filter https://core.trac.wordpress.org/ticket/36687
うん、キャッシュしたいものによっては可能です。私たちのホームページにメインループをキャッシュするために私は同様のことをしました。基本的には、posts_request
とposts_results
を使ってクエリをハイジャックし、代わりにキャッシュをヒットしてから、found_posts
を使ってページネーションを修正することができます。
非常に大まかな例は私たちのコードから引き出された(未テスト)が、あなたはあなたがアイデアを得るのを手伝うべきである:
<?php
/**
* Kill the query if we have the result in the cache
* @var [type]
*/
add_filter( 'posts_request', function( $request, $query ) {
if ( is_home() && $query->is_main_query() ) {
$page = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$key = 'homepage_query_cache_' . $page;
if ( wp_cache_get( $key, 'cache_group' ) )
$request = null;
}
return $request;
}, 10, 2 );
/**
* Get the result from the cache and set it as the query result
* Or add the query result to the cache if it's not there
* @var [type]
*/
add_filter( 'posts_results', function( $posts, $query ) {
if ( is_home() && $query->is_main_query() ) {
$page = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$key = 'homepage_query_cache_' . $page;
if ( $cached_posts = wp_cache_get( $key, 'cache_group' ) ) {
$posts = $cached_posts;
} else {
wp_cache_set( $key . '_found_posts', $query->found_posts, 'cache_group', HOUR_IN_SECONDS );
wp_cache_set( $key, $posts, 'cache_group', HOUR_IN_SECONDS );
}
}
return $posts;
}, 10, 2 );
/**
* Correct the found posts number if we've hijacked the query results
* @var [type]
*/
add_filter( 'found_posts', function( $num, $query ) {
if ( is_home() && $query->is_main_query() ) {
$page = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$key = 'homepage_query_cache_' . $page;
if ( $found_posts = wp_cache_get( $key . '_found_posts', 'cache_group' ) )
$num = $found_posts;
}
return $num;
}, 10, 2 );