web-dev-qa-db-ja.com

意図的に404を取得せずにメインクエリのmax_num_pagesを超えますか?

Author.phpには2つのループがあります。その作者からのすべての投稿を取得するデフォルトのメインループと、$secondloopという別のカスタムWP_Queryです。両方のクエリともposts_per_page 3 に設定されています。 両方のクエリ結果をページ分割したい .

このために$secondloop = new WP_Query($args)に引数を追加しました:

"paged" => (get_query_var('paged')) ? get_query_var('paged') : 1;

(読む:このクエリのページをメインクエリのと同じページに設定してください)。

問題:

  • メインループが私に5つの投稿を与え、私の$secondloopが私に2を与える場合、 page 2 を呼び出しても問題ありません。それは私にメインループからの残りの2つの投稿と私の$secondloopからの投稿を表示しません(それはwhile ($secondloop->have_posts())の中に入らないので)。

  • _ but _ メインループの投稿数が2で$secondloopの投稿数が5の場合、 page 2 を呼び出すと 404 :(となります。代わりに$secondloopの残り2件の投稿が必要です。

メインループからのmax_num_pagesを超えたことをWordPressが検出すると、そこにあるPHPコードは実行されなくなるため、author.phpテンプレート内の何かを変更しても意味がありません。 。

その振る舞いをどうやって "上書き"できますか?


コード:

author.php (ちょうど役に立つビット)

<?php if (have_posts()) { ?>
    <div class="row archive-grid">
        <?php while (have_posts()) : the_post();
            include(locate_template('parts/loop-archive-grid.php'));
            endwhile; ?>
    </div>
<?php }

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$secondloop = new WP_Query(array(
    "post_type"      => "musikalbum",
    "posts_per_page" => 3,
    "author_name"    => get_query_var('author_name'),
    "paged"          => $paged
));

if ($secondloop->have_posts()) { ?>
    <div class="row archive-grid">
        <?php while ($secondloop->have_posts()) : $secondloop->the_post();
            get_template_part( 'parts/loop', 'album-grid' );
        endwhile; ?>
    </div>
    <?php author_page_navi( $loop );
} else {
    joints_page_navi();
} ?>

My functions.php でmy メインクエリposts_per_pageを設定する

function my_post_queries( $query ) {
  if (!is_admin() && $query->is_main_query()){
    if (is_author()){
      $query->set('posts_per_page', 3);
    } else {
      $query->set('posts_per_page', 9);
    }
  }
}
add_action( 'pre_get_posts', 'my_post_queries' );

編集:注意1

ミロは私の functions.php にこれを追加することを提案した答えを私に指摘した。

function my_404_override() {
  global $wp_query;

  if (is_author()) {
    status_header( 200 );
    $wp_query->is_404 = false;
  }
}
add_filter('template_redirect', 'my_404_override');

しかし、それでも404エラーが表示されます。 if節を削除するとindex.phpが表示されますが、これは意図したものではありません。だから私はそのif句が必要です...しかし、WordPressはまだそれを知っていないようです!

コードをテンプレートに直接貼り付けても、get_header();の前の3行であってもうまくいきませんでした。

global $wp_query;
status_header( 200 );
$wp_query->is_404 = false;

編集:感想2

私はtemplate_redirectにフックするためにpre_get_postsを捨てました:

function my_post_queries( $query ) {
  if (!is_admin() && $query->is_main_query()){
    if (is_author()){
      $query->set('posts_per_page', 3);
      // NEW CODE:
      $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
      global $original_page_request; // saves the original value of $paged because I'm about to alter it!
      if ($paged > $query->max_num_pages) {
        $query->set('paged', $query->max_num_pages);
        $original_page_request = $paged;
    } else {
      $query->set('posts_per_page', 9);
    }
 }
}
add_action( 'pre_get_posts', 'my_post_queries' );

そのアイデアは、メインクエリpagedmax_num_pagesを超えたときに手動でリセットし、私のglobal $original_page_requestの "実際のページ"を$secondloopに格納してpagedパラメータをに設定することでした。 残念ながら、うまくいきません。 404が表示されなくなったことをとてもうれしく思いましたが、今度はメインクエリページを自動的に0に設定します。Why 0 ?!

pre_get_postsでは、WordPressが投稿する前にコードが実行されるためです。 $queryへのアクセスはありますが、それはクエリ変数を設定するためだけのもので、検索される投稿がないため、計算するmax_num_pagesはありません。

つまり、max_num_pagesを超えようとしているときにはわからないということです。

それから新しいコードをmy_post_queries( $query )からwpにフックする別の関数にコピーしました。そこでは、max_num_pagesは有効な番号であり、is_author()も正しいです。投稿数を超えても、まだ運がありません。 404.私は$wp_query->is_404 = falseを設定することができました、しかしそれは再びインデックスに私を返します。

2

ページが読み込まれるたびに、WordPressはこれらの機能をそれぞれの順序で実行します。

init();
parse_request($query_args);
send_headers();
query_posts();
handle_404();
register_globals();

メインクエリがquery_posts()の後で終了するところ。 この時点では、WordPressはテンプレートとすべてのクエリ変数を知っています max_num_pagesのように。

handle_404()では、 メインクエリ に投稿がある場合、関数は戻り、WordPressはテンプレートの読み込みを続けます。それ以外の場合は404 HTTPステータスを送信し、代わりに404テンプレートをロードします。

WordPress 4.5以降、pre_handle_404と呼ばれるフィルタフックがあります。これがtrueに設定されている場合、handle_404()は( メインクエリ に投稿があるかどうかにかかわらず)を返し、テンプレートは引き続きロードされます。

そのため、 lot をいじると、これはついにうまくいきます。これをあなたの functions.php に追加してください:

function ignore_404_past_max_page($bool = false, $query) {
  $paged = (get_query_var('paged')) ? intval(get_query_var('paged')) : 1;
  if (is_author() && ($paged > $query->max_num_pages))
    $bool = true;
  return $bool;
}
add_filter( 'pre_handle_404', 'ignore_404_past_max_page', 10, 2);

それでおしまい!既存の関数を編集する必要はありません。クリーンにして、実行したいとおりの処理を実行します。WPを404ingから除外します。 WordPressをバージョン4.5に更新してください (以上)!

不要な副作用として、PHP_INT_MAXまでページングして空のページが表示されることがあります(get_the_author_meta()get_wp_user_avatar()を追加しない限り)。おそらく、データベース内の各作者の最大ページ数を記憶し、それをクエリして$pagedと比較して、上記の関数で$boolfalseに設定できます。しかし、私は 本当に それが現在どのように機能するかに満足しています。

3