情報科学屋さんを目指す人のメモ

方法・手順・解説を書き残すブログ。私と同じことを繰り返さずに済むように。

WordPressで無限リダイレクトが発生したときの対策と調査メモ

WordPress (76)

WordPressサイト内に「ページを開けません。多くのリダイレクトが発生しています」と表示されるページが存在することが分かりました。どうやら、301リダイレクトが繰り返し同じURLへ発生し、無限ループを起こしているようでした。特定のページのみで、.htaccessにも問題がなさそうで困ったのですが、とりあえず回避したときの作業をメモしておきます。

エラー内容

iPhoneで閲覧したとき、次が表示されます。

ページを開けません。多くのリダイレクトが発生しています

Chromeからだとこちら。

このウェブページにはリダイレクトループが含まれています
ERR_TOO_MANY_REDIRECTS

IEだと

このページは表示できません

•Web アドレス http://did2memo.net が正しいか確かめてください。
•検索エンジンでそのページを探してください。
•数分待ってから、ページを最新の情報に更新してください。

Edgeだと

このページを表示できません

対処方法
•Web アドレスが正しいことを確認してください: http://did2memo.net
•ページを最新の情報に更新
•目的の情報を検索する

Microsoftのエラーは不親切です。

Firefoxだとこうなります。

ページの自動転送設定が正しくありません

このアドレスへのリクエストに対するサーバの自動転送設定がループしています。

Cookie を無効化したり拒否していることにより、この問題が発生している可能性もあります。

最初にやってみた対策

今回の対策では、「wp-includes/template-loader.php」の12行目にある「do_action('template_redirect')」をコメントアウト(行頭に「//」を追加)しました

とりあえずこれで今回は問題を回避でき、無限リダイレクトループが発生しないようになりました。

これは、Google検索すると、すぐ出てくる対策ですが、副作用や、どうして直るのか、などが書かれておらず、怪しげな対策でした

do_action('template_redirect')は何をやっているのか

ここで問題なのが、「do_action('template_redirect')」が何をやっているのか、ということなのですが、wordpress全体を検索してみると、このactionにadd_actionしているのは、以下の通りでした。

./wp-includes/class-wp-customize-nav-menus.php:         add_action( 'template_redirect', array( $this, 'render_menu' ) );
./wp-includes/default-filters.php:add_action( 'template_redirect',          'rest_output_link_header', 11, 0 );
./wp-includes/default-filters.php:add_action( 'template_redirect',   'wp_shortlink_header',             11, 0 );
./wp-includes/default-filters.php:add_action( 'template_redirect',  'wp_old_slug_redirect'              );
./wp-includes/default-filters.php:add_action( 'template_redirect', 'redirect_canonical' );
./wp-includes/default-filters.php:add_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
./wp-includes/default-filters.php:add_action( 'template_redirect', '_wp_admin_bar_init', 0 );
./wp-includes/ms-default-filters.php:add_action( 'template_redirect', 'maybe_redirect_404' );
./wp-content/plugins/wp-super-cache/wp-cache.php:add_action( 'template_redirect', 'wp_cache_set_home' );
./wp-content/plugins/wp-super-cache/wp-cache.php:add_action( 'template_redirect', 'wp_cache_catch_404' );
./wp-content/plugins/wp-super-cache/wp-cache-phase2.php:                add_action( 'template_redirect', 'wp_super_cache_query_vars' );
./wp-content/plugins/nginx-champuru/includes/flush-cache.class.php:    add_action("template_redirect", array($this, "template_redirect"), 0);
./wp-content/plugins/nginx-champuru/includes/caching.class.php:    add_action("template_redirect", array($this, "template_redirect"), 9999);
./wp-content/plugins/nginx-champuru/includes/caching.class.php:        add_action('template_redirect', array($this, 'send_http_header_last_modified'));
./wp-content/plugins/google-sitemap-generator-old/sitemap-loader.php:           add_filter('template_redirect', array(__CLASS__, 'DoTemplateRedirect'), 1, 0);
./wp-content/plugins/feedburner-plugin/fdfeedburner.php:add_action('template_redirect', 'feedburner_redirect');
./wp-content/plugins/autoptimize/autoptimize.php:                       add_action('template_redirect','autoptimize_start_buffering',2);
./wp-content/plugins/did2-ab-testing/did2-ab-testing.php:add_action( 'template_redirect', 'did2_ab_testing_start_buffering', 1);
./wp-content/plugins/google-sitemap-generator/sitemap-loader.php:               add_filter('template_redirect', array(__CLASS__, 'DoTemplateRedirect'), 1, 0);
./wp-content/plugins/head-cleaner/head-cleaner.php:                             add_action('template_redirect', array(&$this, 'send_http_header_last_modified'));
./wp-content/plugins/google-publisher/Tags.php:    // initialized wp_query. The template_redirect hook is the first
./wp-content/plugins/google-publisher/Tags.php:    add_action('template_redirect', array($this,

利用停止中のプラグインも含めてこれだけあって確認するのが面倒なのですが、とりあえずいろいろな関数が呼ばれていることが分かります。

ただ、順番に試してみたところでは、プラグインのどれを停止しても、それだけでは問題は解決しませんでした。

wp_old_slug_redirect

というわけで、プラグインではなく、WordPress本体のコードに原因がある、ということで、add_actionを一つずつを潰していく作業をしてみました。

その結果、「wp_old_slug_redirect」が原因であることが分かりました(「./wp-includes/default-filters.php:add_action( 'template_redirect', 'wp_old_slug_redirect');」これ)。

これは名前からして、古いslug(投稿スラッグ、URLなどに使われる、手動で設定する投稿の識別子)にアクセスがあったときに、新しいスラッグへ転送するための関数です。

「wp-includes/query.php」の4986行目に定義されていました。

function wp_old_slug_redirect() {
        global $wp_query, $wp_rewrite;

        if ( '' !== $wp_query->query_vars['name'] ) :
                global $wpdb;

                // Guess the current post_type based on the query vars.
                if ( get_query_var( 'post_type' ) ) {
                        $post_type = get_query_var( 'post_type' );
                } elseif ( get_query_var( 'attachment' ) ) {
                        $post_type = 'attachment';
                } elseif ( ! empty( $wp_query->query_vars['pagename'] ) ) {
                        $post_type = 'page';
                } else {
                        $post_type = 'post';
                }

                if ( is_array( $post_type ) ) {
                        if ( count( $post_type ) > 1 )
                                return;
                        $post_type = reset( $post_type );
                }

                // Do not attempt redirect for hierarchical post types
                if ( is_post_type_hierarchical( $post_type ) )
                        return;

                $query = $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, $wp_query->query_vars['name']);

                // if year, monthnum, or day have been specified, make our query more precise
                // just in case there are multiple identical _wp_old_slug values
                if ( '' != $wp_query->query_vars['year'] )
                        $query .= $wpdb->prepare(" AND YEAR(post_date) = %d", $wp_query->query_vars['year']);
                if ( '' != $wp_query->query_vars['monthnum'] )
                        $query .= $wpdb->prepare(" AND MONTH(post_date) = %d", $wp_query->query_vars['monthnum']);
                if ( '' != $wp_query->query_vars['day'] )
                        $query .= $wpdb->prepare(" AND DAYOFMONTH(post_date) = %d", $wp_query->query_vars['day']);

                $id = (int) $wpdb->get_var($query);

                if ( ! $id )
                        return;

                $link = get_permalink( $id );

                if ( is_feed() ) {
                        $link = user_trailingslashit( trailingslashit( $link ) . 'feed' );
                } elseif ( isset( $GLOBALS['wp_query']->query_vars['paged'] ) && $GLOBALS['wp_query']->query_vars['paged'] > 1 ) {
                        $link = user_trailingslashit( trailingslashit( $link ) . 'page/' . $GLOBALS['wp_query']->query_vars['paged'] );
                } elseif( is_embed() ) {
                        $link = user_trailingslashit( trailingslashit( $link ) . 'embed' );
                } elseif ( is_404() ) {
                        // Add rewrite endpoints if necessary.
                        foreach ( $wp_rewrite->endpoints as $endpoint ) {
                                if ( $endpoint[2] && false !== get_query_var( $endpoint[2], false ) ) {
                                        $link = user_trailingslashit( trailingslashit( $link ) . $endpoint[1] );
                                }
                        }
                }

                /**
                 * Filter the old slug redirect URL.
                 *
                 * @since 4.4.0
                 *
                 * @param string $link The redirect URL.
                 */
                $link = apply_filters( 'old_slug_redirect_url', $link );

                if ( ! $link ) {
                        return;
                }

                wp_redirect( $link, 301 ); // Permanent redirect
                exit;
        endif;
}

とりあえず、自身にリダイレクトされていないことへのチェック漏れが気になりました。

不具合

これについて、検索してみると、次の不具合報告が見つかりました。

#35012 (wp_old_slug_redirect can cause redirect loop) – WordPress Trac

重要なのは、次の記述でした。

Milestone changed from Awaiting Review to 4.4.1 引用元

このあと、このmilestoneは削除されているのですが、とりあえず現在WordPressのバージョンが4.4.0で、まさに今、なタイミングだと気が付いたので、アップデートしてみることにしました。

直った!

するとWordPress 4.4.1 へのアップデート後、今回のリダイレクトループは解消されました

謎のコメントアウトに比べると、遙かにスッキリできました。めでたしめでたし。

コメント(0)

新しいコメントを投稿