7

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:

http://example.com/wp-content/plugin/data-fetcher/list-data.php

-> 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]
</IfModule>

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?

2 Answers 2

6

Mark,

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:

12
  • 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
    Commented Jan 13, 2011 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
    Commented Jan 13, 2011 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
    Commented Jan 14, 2011 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
    Commented Jan 14, 2011 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
    Commented Jan 17, 2011 at 7:27
10

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' );
        exit();
    }
}

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

3
  • 1
    This is the correct way to do it.
    – scribu
    Commented Oct 3, 2011 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.
    – codingbbq
    Commented Jan 11, 2013 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
    Commented Jan 13, 2013 at 19:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.