Redirects are one of the trickiest things to troubleshoot and can cause lots of coffee drinking and possibly sleepless nights :)

Here's a video explanation for the whole process.

I had to troubleshoot redirect loop issue with one of my recently semi-launched products: EasyWPHost.

 

The Issue

The issue was when the user tried to register WordPress would redirect to default WordPress registration page and then do another redirect to the registration page that was provided by the Membership plugin. It was weird & frustrating. I've even installed xdebug extension to find out what's causing this but setting the debugger & IDE would have been time consuming .
I have used Membership2 plugin from WPMUDEV. The funny thing is that I was 99% sure that it was the membership plugin that was causing the issue as all the leads were pointing to it. When I disable the content protection from its settings page the site would work normally.
Adam and Predrag from WPMUDEV team tried very hard to troubleshoot the issue but since I am an advanced developer I also make advanced and hard to find bugs :)

 

Cause

It turned out that I had my own redirect rules for links that contain the text: signup, join, register to redirect to the registration page. In hindsight it would have been better for me to hook into a 404 action/filter and then do my own processing. The logic should have been if a page doesn't exist process it... but we can only connect the dots looking backward, right?

 

The solution
I find this part the most important/interesting part.

I just couldn't let the issue go. I even dreamt about it. I hate leaving issues unresolved because they consume mental energy.  I was also curious was causing this. I remembered that WordPress has lots of hooks (filters and actions) and php has a great function called debug_backtrace().

debug_backtrace is a super awesome function because it shows function calls that were executed before the current function is executed, the exact lines the function was called from, originating file, function arguments etc.
The debug output looks like this.

Mon, 21 Nov 2016 07:42:42 +0000 IP: 127.0.0.1 location: [http://easywphost.com/app/manage/], status [301]
Backtrace
array (
  0 => 
  array (
    'file' => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-includes\\plugin.php',
    'line' => 235,
    'function' => 'orb_dbg_redirect_trbl',
    'args' => 
    array (
      0 => 'http://easywphost.com/app/manage/',
      1 => 301,
    ),
  ),
  1 => 
  array (
    'file' => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-includes\\pluggable.php',
    'line' => 1154,
    'function' => 'apply_filters',
    'args' => 
    array (
      0 => 'wp_redirect',
      1 => 'http://easywphost.com/app/manage/',
      2 => 301,
    ),
  ),
  2 => 
  array (
    'file' => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-includes\\canonical.php',
    'line' => 516,
    'function' => 'wp_redirect',
    'args' => 
    array (
      0 => 'http://easywphost.com/app/manage/',
      1 => 301,
    ),
  ),
  3 => 
  array (
    'file' => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-includes\\plugin.php',
    'line' => 524,
    'function' => 'redirect_canonical',
    'args' => 
    array (
      0 => 'http://easywphost.com/app/manage',
    ),
  ),
  4 => 
  array (
    'file' => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-includes\\template-loader.php',
    'line' => 12,
    'function' => 'do_action',
    'args' => 
    array (
      0 => 'template_redirect',
    ),
  ),
  5 => 
  array (
    'file' => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-blog-header.php',
    'line' => 19,
    'args' => 
    array (
      0 => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-includes\\template-loader.php',
    ),
    'function' => 'require_once',
  ),
  6 => 
  array (
    'file' => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\index.php',
    'line' => 17,
    'args' => 
    array (
      0 => 'C:\\Copy\\Dropbox\\cloud\\projects\\clients\\easywphost.com\\htdocs\\wp-blog-header.php',
    ),
    'function' => 'require',
  ),
)

-----------------------------------------------------

 

I have created a system (mu-plugin) that hooked into "wp_redirect" filter. This directly pointed me in the right direction. It was one of my plugins. Damn, that's embarrassing. I probably have wasted 1-3 hours of the WPMUDEV folks. Sorry, about that.

 

Create a file in wp-content/mu-plugins/dbg_redir.php
If the wp-content/mu-plugins/ folder doesn't exist, create it.
The plugins in that folder are automatically activated.
Make sure you remove the file when you're done.
It will create a zzz_redir.log file in the root folder of WordPress (where wp-config.php file is).
The log file starts with zzz so it's shows up last in the file list.

<?php

/**
 * This logs all the redirects.
 * This is used for troubleshooting redirect loops.
 * @author Svetoslav (Slavi) Marinov | http://orbisius.com
 */
add_filter( 'wp_redirect', 'orb_dbg_redirect_trbl', 100, 2 );

/**
 *
 * @param str $location
 * @param int $status
 * @return str
 */
function orb_dbg_redirect_trbl( $location, $status ) {
    $buff = '';
    $buff .= date( 'r' ) . ' ';
    $buff .= 'IP: ' . $_SERVER['REMOTE_ADDR'] . ' ';
    $buff .= "Location: [$location], Status [$status]\n";
    $buff .= "Backtrace\n";
    $buff .= var_export( debug_backtrace(), 1 ) . "\n";
    $buff .= "\n-----------------------------------------------------\n\n";

    // Save the logs in the root wp folder.
    // The file starts with zzz so it's shows up last in the file list.
    file_put_contents( ABSPATH . 'zzz_redir.log', $buff, LOCK_EX | FILE_APPEND );
    
    return $location;
}

 

I was able to solve it because I have used standard WordPress functions instead of providing my own implementation for the redirection.