WordPress Custom Post Type Permalink Below Root Directory

I have wordpress installed in the /blog/ directory on my web server, so the WordPress homepage is at, for example http://www.example.com/blog/

I am creating some custom post types for content management. I would like the URL for the “product” custom type to be http://www.example.com/product/… and for the “people” custom type to be http://www.example.com/people/

Read More

Now server side this is simple. The problem is making WordPress generate (rewrite) the permalinks so they are below the WordPress Installation/Root directory (/home/site/public_html/blog -> http://www.example.com/blog/).

I could do if by using PHP output buffers to search-n-replace so that the string “http://www.example.com/blog/product” is replaced with “http://www.example.com/product“, but that is messy and will use up a lot more RAM. If there is an official or correct non-hacky way to do this, I would much rather do that.

Does anyone know how to do this?

Related posts

Leave a Reply

1 comment

  1. If WordPress is handling both the blog and the pages for the products and peoples, you may want to rethink your folder structure. You can still keep most of WordPress where it is (the /blog/ subdirectory), and move its index.php and .htaccess files up to the root. See Giving WordPress Its Own Directory: Using a pre-existing subdirectory install.

    That being said, if you really don’t want to move anything, then you need a more complicated programmatic solution. For that, you need to use the WordPress Rewrite API. The trick is to use its various functions (add_rewrite_rule, add_rewrite_tag, etc.) to create a set of rules WordPress will recognize but then write your own .htaccess file in the root of your website, above the WordPress root folder.

    So, if you did something like this…

    <?php
    // Set up the higher-level (non-WordPress) rewrite rules
    // so that you redirect non-WP requests to your own WP install.
    function make_my_redirects () {
        global $wp_rewrite;
        add_rewrite_rule('^product/', '/blog/index.php?post_type=product', 'top');
        add_rewrite_rule('^people/', '/blog/index.php?post_type=people', 'top');
    
        // Save original values used by mod_rewrite_rules() for reference.
        $wp_home = home_url(); // get the old home
        update_option('home', '/'); // change to what you need
        $wp_index = $wp_rewrite->index;
        $wp_rewrite->index = 'blog/index.php';
    
        // Then actually call generate the .htaccess file rules as a string.
        $htaccess = $wp_rewrite->mod_rewrite_rules();
    
        // and write the string outside the WordPress root.
        file_put_contents(
            trailingslashit(dirname(ABSPATH)) . '.htaccess',
            $htaccess,
            FILE_APPEND
        );
    
        // Don't forget to set the original values back. :)
        $wp_rewrite->index = $wp_index;
        update_option('home', $wp_home);
    }
    register_activation_hook(__FILE__, 'make_my_redirects');
    

    …then you will have something like this inside of your /home/site/public_html/.htaccess file:

    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^product/ /blog/index.php?post_type=product [QSA,L]
    RewriteRule ^people/ /blog/index.php?post_type=people [QSA,L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /blog/index.php [L]
    </IfModule>
    

    So, is it possible? Yeah, I guess. Is it recommended? Probably not. 🙂 Easier to just give WordPress its own directory.