1

Question

What'd be an optimal way to redirect the home page of a WordPress site to a category archive without involving external factors (e.g. Apache's .htaccess) i.e. within WordPress?

Why?

(Only to justify the question. Please let this not turn the question into too localized.)

It's a news site. The categories are used as Editions, for example:

  • US: http://example.com/main/
  • UK: http://example.com/uk/
  • Japan: http://example.com/jp/

(The category based is removed.)

The visitor is to be taken to the US edition (http://example.com/main/) by default no matter where he/she is from, and that is why I want the redirect.

Options Considered

I know I can simply modify the main query and have the home page only include posts from the specific category (Edition). But the way the features of the site are constructed, I find the redirect to be more feasible and moreover appropriate.

Aside from that, I want the URLs to make the current location clear to the visitor.

As for why I can't use the simpler and better performant .htaccess-based redirection -- all the functionality needs to be either within the theme or as a separate plugin. Hence, looking for the best way to do it with WordPress/PHP.

I've also considered adding this in home.php template file:

<?php
    wp_redirect( 'http://example.com/main/' );
?>

And decided against it as it "almost doubles server load for home page".

  • 1
    What criteria are you planning on using to determine whether someone gets the /main/ or the /jp/ editions? I would think a wp_redirect() based on that criteria could redirect you to the category URL. – GhostToast Nov 5 '13 at 15:13
  • @GhostToast The edited question has the detailed cleared out. (I was actually making the edit before you posted your comment.) – its_me Nov 5 '13 at 15:15
  • In short you want do a redirect but you don't want load WP core 2 times. And you want get this result using WordPress: is not possible: how can WordPress do the redirect without loading the core? So make a choice: do redirect using WordPress (you have to load the core) or do redirect without WordPress and so use .htaccess redirection. If you choose WordPress way you can use a MU pluging, in this way you avoid loading regular plugins and theme. IMHO best solution is not to redirect at all, and change main query, but this is an opinion. – gmazzap Nov 5 '13 at 15:28
3

Eliminating all of the other solutions, there is at least one remaining: template_redirect:

function wpse121308_redirect_homepage() {
    // Check for blog posts index
    // NOT site front page, 
    // which would be is_front_page()
    if ( is_home() ) {
        wp_redirect( get_category_link( $id ) );
        exit();
    }
}
add_action( 'template_redirect', 'wpse121308_redirect_homepage' );

You will need to pass the appropriate category $id, of course.

The benefit of redirecting at template_redirect is that you only get one template-load taking place, rather than a second redirect after the template loads.

Edit

As per @Milo's comment, you could also try hooking into the process even earlier, at pre_get_posts, thereby potentially saving an entire query request:

add_action( 'pre_get_posts', 'wpse121308_redirect_homepage' );
  • why not hook pre_get_posts and save a query? – Milo Nov 5 '13 at 15:31
  • @Milo mainly because I've never tried redirecting at pre_get_posts? :) – Chip Bennett Nov 5 '13 at 15:33
  • @ChipBennett : You can redirect from anywhere before headers are sent. – s_ha_dum Nov 5 '13 at 15:36
  • So, really, the answer here is: perform the redirect as early as the $query variables are defined (parse_request? pre_get_posts?), but no later than template_redirect. – Chip Bennett Nov 5 '13 at 15:39
  • 1
    "is_home() uses the global $wp_query WP_Query object. is_home() isn't usable before the parse_query action." Therefore we can use parse_query (NOT parse_request) instead of pre_get_posts. I checked and it works! But I am not sure if it's in anyway better than pre_get_posts. (Related) – its_me Nov 6 '13 at 9:43
1

I wrote 2 comments, however now I have more time and want to add an answer that can be useful for someone.

The problem is this: once we want redirect is triggered by WordPress we must load WordPress 2 times: firs to do the redirect, second time to show the desired home page.

So my thought less I load before redirect, faster will be entire process, and less the server load.

The first not core items loaded by WordPress are MU plugins. So I think best place to do what we want is a Mu plugin.

The problem we have to face is that when MU plugins load, we don't know the query, and alo conditional tag don't work. However in this specific case, we want to redirect when we are in the home url, and it is easy to recognize looking at url.

Second little problem is how to know the link where redirect home page. We can hardcoding it in the plugin code, but is not an elegant solution. We can run a get_category_link, but once we are persecuting performance is not ideal, I think a good compromise can be hardcoding it in wp-config.php.

So, open wp-config.php and add

define( 'WP_SITEURL', 'http://www.example.com' );
define('THEHOMEPAGEREDIRECT', WP_SITEURL . '/main');

Then create a file, name it thehomepageredirector.php and save if in MU plugins folder.

By default this folder is called mu-plugins and it is inside wp-content folder (beside plugins folder). MU plugins don't need to be activated.

In this file you should put only:

if ( ! defined('THEHOMEPAGEREDIRECT') ) return;
$home_path = trim( \parse_url( home_url(), PHP_URL_PATH ), '/' );
$url = str_replace( $home_path, '', add_query_arg( array() ) );
if ( $url === '/' ) {
  // pluggable is loaded after MU plugins
  require( ABSPATH . WPINC . '/pluggable.php' );
  wp_safe_redirect(THEHOMEPAGEREDIRECT, 301);
  exit();
}

In this way the redirect happen when you visit http://www.example.com and it happen before any plugins and theme are loaded, before query fires, before a lot of hooks are triggered... before a lot of stuff.

Edit

Is also possible not trigger the redirect when non valid or empty query string are in the url:

/**
 * Class used only to retrieve all the valid query vars
 */
class WP_Extend extends WP {
  public $all_vars;
  function __construct() {
   $this->all_vars = array_merge($this->public_query_vars, $this->private_query_vars);
  }
}

if ( ! defined('THEHOMEPAGEREDIRECT') ) return;
$home_path = trim( \parse_url( home_url(), PHP_URL_PATH ), '/' );
$url = str_replace( $home_path, '', add_query_arg( array() ) );
$url_array = \explode( '?', $url );
if ( count($url_array) > 1 ) {
  $qs = array();
  parse_str( $url_array[1], $qs );
  $good = array_filter($qs);
  // do not redirect if empty query string are in the url
  if ( empty ( $good  ) ) return;
  $wpe = new WP_Extend;
  $valid = array_intersect( array_keys($good), $wpe->all_vars );
  // do not redirect if not valid query string are in the url
  if ( count( $good ) != count($valid)  ) return;
}
if ( $url === '/' ) {
  // pluggable is loaded after MU plugins
  require( ABSPATH . WPINC . '/pluggable.php' );
  wp_safe_redirect(THEHOMEPAGEREDIRECT, 301);
  exit();
}
  • Kinda clever solution. As I see it, this'll make it similar to .htaccess redirect which we avoided for a reason i.e. we'll need various checks in place so that valid query strings aren't redirected (e.g. example.com/?category_name=xxx&tag=yyy), invalid or empty query strings ARE redirected, home page pagination IS redirected, etc. Thus the complexity grows, and it's always possible that I am missing something else. Therefore I guess I'll have to stick with the function that hooks into pre_get_posts, like Chip suggested in his answer. – its_me Nov 6 '13 at 4:05
  • By the way, this's how I am doing it now (a must-use plugin like you suggested!): pastebin.com/raw.php?i=Uuqj0uQ9 -- it lets wordpress take care of all the guess work i.e. if the query strings are valid, if it's home page or home page's pagination, etc. Given the case, what do you think? Have a better idea? – its_me Nov 6 '13 at 4:14
  • @its_me Regarding pagination, I think you should not have example.com/page/2/ but always example.com/main/page/2/. Also note that with my code home url containing query string is not redirected only way to get a redirect is the url is http://example.com or http://example.com/. anything different does not trigger the redirect. – gmazzap Nov 6 '13 at 4:29
  • Maybe I wasn't clear enough. I meant, with your function in place example.com/page/2/ isn't getting redirected. On the other hand, yes, your solution doesn't redirect query strings, but it's also not redirecting INVALID/EMPTY query strings. Hope I am clear. Thanks for your time! – its_me Nov 6 '13 at 4:38
  • e.g. of invalid query string is example.com/?ksjdlkjdl=sdkdjksd i.e. a query string that WP doesn't recognize. e.g. of empty query string is example.com/?category_name (without any value) – its_me Nov 6 '13 at 4:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.