私のサイトでは、ユーザーが静的ホームページを閲覧している場合、いくつかのフィルターを適用する必要があります。私の理解するところでは、 is_front_page()
がそうであるかどうかを判断するべきです。
しかし、この関数を使用するときはいつでもtrue
を返すことがありますが(例:posts_orderby
)、ほとんどの場合はfalse
を返します(例:pre_get_posts
、posts_fields
、posts_join
、posts_where
)。結果にかかわらず、私は常に次の通知を受け取ります -
4373行目で{my_path}\wp-includes\query.php内の非オブジェクトのプロパティを取得しようとしています
問題のある行を含むメソッドはWP_Query::is_front_page()
- です。
public function is_front_page() {
// most likely case
if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
return true;
/** The offending line */ elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
return true;
else
return false;
}
この問題に対処するために、以下のように私は自分自身の機能を作成しましたが、そうする必要があるのは「汚い」ようです。だから私の質問はこうです - これを行うより良い方法はありますか?
function fgw_is_front_page($q){
if(!is_a($q, 'WP_Query'))
return false;
return (get_option('show_on_front') == 'page' && get_option('page_on_front') && $q->get('page_id') == get_option('page_on_front'));
}
さらに調査してみると、問題の行は実際には4369(wp-includes/querey.php)であると思われます - $page_obj = $this->get_queried_object();
$page_obj
はnull
として返されています。つまり、$q->is_front_page()
のチェックは失敗します。これは間違っているように思われます、そして、誰かがこれがどのようにして予想される振る舞いであるかを説明することができない限り、私はTracでチケットを開くことを見るつもりです。
私は今、上記の機能を修正しました。@ birgireで説明されているように、私が使用しているすべてのフィルタ(WP_Queryインスタンス)に渡された2番目の引数を使用することで、グローバルを廃止することができました。
しかし、以下の例では、$q->is_front_page()
をチェックするときに、まだ前述の通知(およびfalse
の結果)を受け取っています -
add_filter('posts_fields','fgw_index_posts_fields', 10, 2);
function fgw_index_posts_fields($fields, $q){
global $wpdb;
if(!is_admin() && is_main_query() && (is_home() || $q->is_front_page($q)))
$fields.= $wpdb->prepare(', %1$s.name as category_name', $wpdb->terms);
return $fields;
}
$q->is_front_page()
をfgw_is_front_page($q)
に置き換えることはできますが、既に存在するものがあると思われる場合にも、カスタムソリューションを使用する必要があるのは面倒です。
posts_orderby
、posts_where
、posts_join
およびposts_clauses
フックに関しては、現在の\WP_Query
オブジェクトはsecond入力引数を通して利用可能です。
これらは\WP_Query
クラスの関連部分です。
$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
$where = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
$join = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
apply_filters_ref_array
関数と&$this
を使用しているものはすべて現在の\WP_Query
インスタンスです。コーデックスはこの機能について次のように述べています。
この関数は
apply_filters
と同じですが、$ tagにフックされた関数に渡される引数は配列を使って提供されます。
2番目の引数には、たとえば次のようにしてアクセスできます。
add_filter( 'posts_where', function( $where, \WP_Query $q )
{
if( $q->is_front_page() ) <-- This method won't work here with a static front-page!!!
{
// ...
}
}, 10, 2 );
そのため、グローバルな$wp_query
オブジェクトに頼る必要はありません。
これをWP_Query
内でトレースした後、is_front_page()
メソッドの呼び出しがこれらのフィルターコールバック内では機能しない理由がわかりました。まだ返すオブジェクトを持っていないis_page()
メソッドを使おうとするget_queried_object()
メソッドに問題があります。
一方、is_home()
メソッドは機能し、is_page()
メソッドは呼び出しません。
少なくとも2つのTracチケット、 #27015 と #21790 がこの問題に関連しているようです。
#27015には@mattonomicsによる patch の提案があり、これはparse_query()
メソッド内のqueried_object
オブジェクトを修正します。
それでは、私たちの場合ではなく、代わりにparse_query
フックを使ってこれらの変更を試してみてください。
/**
* A workaround for the is_front_page() check inside pre_get_posts and later hooks.
*
* Based on the patch from @mattonomics in #27015
*
* @see http://wordpress.stackexchange.com/a/188320/26350
*/
add_action( 'parse_query', function( $q )
{
if( is_null( $q->queried_object ) && $q->get( 'page_id' ) )
{
$q->queried_object = get_post( $q->get( 'page_id' ) );
$q->queried_object_id = (int) $q->get( 'page_id' );
}
} );
そのパッチから、このようにしてさらに変更を加えることができるはずです。
の代わりに
$query->is_front_page()
使ってみてください
$query->get('page_id') == get_option('page_on_front')
(コンテキスト:)
function custom_pre_get_posts( $query ) {
if ( $query->get('page_id') == get_option('page_on_front') ) {
// do stuff
}
}
add_action('pre_get_posts', 'custom_pre_get_posts');
この解決策はこちらから: https://core.trac.wordpress.org/ticket/21790#comment:11