WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In my WordPress plugin I have a php file that generates some stats about the blog and outputs it as a simple text file. To access WordPress functions I've included this at the top of the file:

define('WP_USE_THEMES', false);
require(dirname(__FILE__) . '/../../../wp-blog-header.php');

Now I'd like to hide the actual URL, since it's in the wp-content/plugins directory and replace it with something nice and short:


-> rewrite to http://example.com/list-data

I added this to .htaccess:

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteRule ^list-data$ wp-content/plugins/data-fetcher/list-data.php [L]

The problem: when I access the short URL, I get a 301 Moved Permanently redirect before I end up on the page. This means that the wp-content/plugins/... URL is revealed in the browser.

I suspect that WordPress is initiating this somehow. The rewrite rule works fine for images and plain php files (i.e. without WP includes/require).

Is my assumption correct? How can I prevent WordPress from sending the redirect?

share|improve this question
up vote 5 down vote accepted


I hate to say it, but you're going about this the wrong way. PHP files in your plug-in should never be accessed directly in this way. Instead, they should be loaded from within WordPress just like everything else.

Here are some alternative paths you could take:

Create an admin page that displays your stats

This is a page accessible from within WordPress by authenticated users only. If you use the correct API, this page will look very clean and will display your simple stats however you want. Since it's inside WordPress to begin with, you'll already have access to the entire WP API without needing to load wp-blog-header.php directly.

Use your existing system, but register the rewrite with WordPress

You should never modify your .htaccess file directly. This file can be changed when you add new plug-ins or change your permalink structure, meaning you'll lose your customizations. Instead, you can create a custom rewrite by making a function call within WordPress itself:

add_action( 'init', 'my_rewrite' );
function my_rewrite() {
    global $wp_rewrite;

    add_rewrite_rule('list-data/$', WP_PLUGIN_URL . '/data-fetcher/list-data.php', 'top');
    $wp_rewrite->flush_rules(true);  // This should really be done in a plugin activation

This will add your custom rule to the top of the WordPress rewrite rules and should skip any other redirects WordPress matches against the regex.

For a great example of how you can implement this kind of simple rewriting in a plug-in, check out Ozh's tutorial on redirecting a pretty login URL:

share|improve this answer
If you're going to update .htaccess, shouldn't that be a hard flush (and pass true as a parameter)? And $wp_rewrite is a global variable. Of course, if you do this only once (not for a plugin that should be distributed), you can also leave out the flush_rules() line and just visit the Permalinks page, which will flush your rules anyway. – Jan Fabry Jan 13 '11 at 16:17
Right and right ... updated accordingly. The only reason I add flush_rules() here is so that adding the rule is a one-step process (i.e. you activate the plug-in) rather than activating it and then pushing the change by going to another page. – EAMann Jan 13 '11 at 16:48
Thanks, I'll try that and let you know if it works. My WP install is in a subdirectory /wordpress/. Will the redirect start with /wp-contents anyway? – Mark Jan 14 '11 at 11:41
You'll have to give it a try and see. But the re-written URL is meant to be relative to the WordPress installation. – EAMann Jan 14 '11 at 15:11
Thanks for the link to the example. That did the trick for me. One additional catch: first I had this pattern: "^list-data$", but it turns out that it has to be "list-data$". – Mark Jan 17 '11 at 7:27

You can also set a custom variable inside WordPress when your URL is accessed. You can then later check for this variable and if it exists, do whatever you want to do.

In this example, we will use wpse6891_stats as our variable.

// Register a URL that will set this variable to true
add_action( 'init', 'wpse6891_init' );
function wpse6891_init() {
    add_rewrite_rule( '^stats$', 'index.php?wpse6891_stats=true', 'top' );

// But WordPress has a whitelist of variables it allows, so we must put it on that list
add_action( 'query_vars', 'wpse6891_query_vars' );
function wpse6891_query_vars( $query_vars )
    $query_vars[] = 'wpse6891_stats';
    return $query_vars;

// If this is done, we can access it later
// This example checks very early in the process:
// if the variable is set, we include our page and stop execution after it
add_action( 'parse_request', 'wpse6891_parse_request' );
function wpse6891_parse_request( &$wp )
    if ( array_key_exists( 'wpse6891_stats', $wp->query_vars ) ) {
        include( dirname( __FILE__ ) . '/stats.php' );

You can also do the check later, with get_query_var( 'wpse6891_stats' ).

share|improve this answer
This is the correct way to do it. – scribu Oct 3 '11 at 14:26
You mean to say that we have to write this in functions.php in our themes folder? can you help me as to where do i write this code? Thank you in advance. – noobcode Jan 11 '13 at 10:05
@noobcode: If you use this in a theme, you place it in functions.php. If you use it in a plugin, you place it in the plugin code. – Jan Fabry Jan 13 '13 at 19:46

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.