web-dev-qa-db-ja.com

条件付きクエリを強制するには?

カスタムクエリ変数が登録されてクエリ文字列に存在する場合、is_front_page()であってもクエリが'page' == get_option( 'show_on_front' ) trueに設定されないという長年のWordPressコアバグ( #16373 )があります。完全な詳細はtracチケットにありますが、最終的にはフロントページがget_option( 'page_on_front' )ではなく無効なページを返します。

私は、フロントページのクエリ文字列にカスタムクエリ変数を渡す必要があるという特定のユースケースを持っています(登録されたクエリ変数を渡すためのフォームを使用し、順番にテーマオプションをフィルタリングする - フロントエンドテーマオプションデモ)上記のtracのチケットは無効としてクローズされたので、回避策が必要です。

次のように、フロントページのテンプレートを簡単に十分に強制することができます。

function themeslug_force_front_page_template( $template ) {
    if ( '' != get_query_var( 'foobar' ) ) { // Registered custom query var
        return get_front_page_template();
    }
    return $template;
}
add_filter( 'template_include', 'themeslug_force_front_page_template' );

ただし、基になるクエリ条件は影響を受けません。そのため、is_front_page()trueであることに依存するコード(サイトのフロントページにのみ表示されるスライダなど)は、まだ正しく表示されません。

$querypre_get_postsに変更しようとしましたが、これはうまくいかないようです。

function themeslug_force_static_front_page( $query ) {
    if ( $query->is_main_query() ) {
        if ( 'page' == get_option( 'show_on_front' ) ) {
            if ( '' != get_query_var( 'foobar' ) ) { // Registered custom query var
                $query->set( 'page_id', get_option( 'page_on_front' ) );
                $query->set( 'is_home', false );
                $query->set( 'is_page', true );
                $query->set( 'is_front_page', true );
            }
        }
    }
}
add_action( 'pre_get_posts', 'themeslug_force_static_front_page' );

照会条件は変更されません。コールバック内で誤って試行していますか?特にis_front_page()というクエリ条件を強制するための別の、あるいはより良い方法はありますか?

編集する

page_iddoesの設定はpre_get_postsコールバックで機能することに注意してください。

$query->set( 'page_id', get_option( 'page_on_front' ) );

template_includeフィルタを省略した場合、表示されるページは実際にはフロントページに割り当てられているページです。ただし、get_page_template()ではなくget_front_page_template()が使用されます。そのため、page_idpre_get_postsを設定すると、is_page()がtrueになります。しかし、前述のバグはis_front_page()trueに設定されるのを防ぎます。

編集2

@ toschoの要求ごとに、ここにコンテキスト用のいくつかのquery varコードを示します。

クエリ変数を登録します。

/**
 * Add options-related query variables
 */
function themslug_add_theme_demo_query_vars( $qvars ) {
    $qvars[] = 'demo_foo';
    $qvars[] = 'demo_bar';
    $qvars[] = 'demo_baz';
    return $qvars;
}
add_filter( 'query_vars', 'themeslug_add_theme_demo_query_vars' );

foobar、およびbazはテーマオプション - 背景、さまざまな色など)

それらがどのように使われるかは単にテーマオプションにフィルタを追加することです - その部分は質問の範囲外であるので、ここではそれを省略します。

それらはカスタムウィジェット経由でフロントエンドに出力されます。ウィジェットの出力は単なるフォームです。これがフォームフィールドの一例です。

<h3>Foo</h3>
<input name="demo_foo" id="demo_foo" class="pickcolor"  type="text" value="<?php echo $foo_setting; ?>" data-default-color="<?php echo $foo_setting; ?>" />

送信時に生成されたクエリ文字列:

www.example.com/?foo=some_value
7
Chip Bennett

is_front_page() のどの部分でfalseが返されるのかを確認しましたか?

私は問題解決のためにTracのチケットからの設定に従うことで再現することができました。私の場合、この関数の中で is_page() への呼び出しはfalseを返していました。

これはpage_id$wp_query->set()を使用したことが原因で、is_pagequery_varsを変更するだけで、「クエリの状態」自体を変更することはないと思います。

この2行をコードに追加することで、これに対する回避策を作成できました。

$query->is_page = true;
$query->queried_object = get_post(get_option('page_on_front') );

(私の設定では)URLが(query_varがURLにあっても)フロントページに正しく表示され、is_front_page()trueを返すという結果になりました。

私はこれがあなたをいくらかさらに助けていることを願っています。


WP_Query クラスの定義を見ると、変数$query_varsと変数$is_pageがあることがわかります。

あなたが使ったset関数($query->set( 'is_page', true );)は query var をセットするだけです:

function set($query_var, $value) {
    $this->query_vars[$query_var] = $value;
}

$query->is_page = trueに保存されている状態情報は変更されず、代わりにクエリvar $query->query_vars['is_page'] = trueが設定されます。

あなたがOOPアプローチから来て、WP_Query::set()を古典的なクラス設定関数として理解するならば、それは少し誤解を招くようなものです - そうではありません。

7
s1lv3r

私はそのTracチケットでも答えました、しかしここでの基本問題はこれよりずっと簡単であると思います。

Demo_foo、demo_bar、demo_bazを "クエリ変数"としてフックしていますが、そうではありません。少なくとも、意図した意味ではありません。

URLの後の?foo = bar文字列はしばしばクエリ文字列と呼ばれますが、「クエリ変数」は実際にはメインクエリに影響を与える単なる変数です。変数をフックしなくても消えず、メインのWP_Queryオブジェクトに読み込まれません。

そしてあなたの場合、それはまさにあなたが望むものであるように見えます。あなたの変数はテーマのオプションであり、それらはメインのQueryの一部ではありません(データベースから投稿を取得します)。表示する投稿を選択するためにそれらを使用しているのではなく、テーマのオプションなどを設定するためにそれらを使用しています。

あなたがそれらをquery_varsとしてフックしないのであれば、それらはメインのWP_Queryオブジェクトにまったく影響を与えません。 get_query_varを使用する代わりにメインの$ _GETスーパーグローバルからそれらを取得する必要があります。また、反射型XSS攻撃を防ぐために適切なサニタイズを実行する必要があります。追加の回避策を追加するのではなく、最初の段階で問題の原因となっているコード。

3
Otto