web-dev-qa-db-ja.com

'pre_get_posts'や 'posts_where'などのフィルタを使用するときに 'is_front_page'を決定するための正しい方法は何ですか?

私のサイトでは、ユーザーが静的ホームページを閲覧している場合、いくつかのフィルターを適用する必要があります。私の理解するところでは、 is_front_page() がそうであるかどうかを判断するべきです。

しかし、この関数を使用するときはいつでもtrueを返すことがありますが(例:posts_orderby)、ほとんどの場合はfalseを返します(例:pre_get_postsposts_fieldsposts_joinposts_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_objnullとして返されています。つまり、$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)に置き換えることはできますが、既に存在するものがあると思われる場合にも、カスタムソリューションを使用する必要があるのは面倒です。

5
David Gard

posts_orderbyposts_whereposts_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' );
    }
} );

そのパッチから、このようにしてさらに変更を加えることができるはずです。

5
birgire

の代わりに

$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

0
squarecandy