Archive permalinks

This site has been very helpful for me in learning how to rewrite permalinks using add_filters to solve issues we were having when we merged two blogs into one. But, I do have one item I have been unable to find any tips for:

On the date based archives links, i.e. www.domain.com/2011/12/

Read More

I simply want to translate them to: www.domain.com/news/2011/12/

Thanks in advance for any assistance.

Related posts

Leave a Reply

2 comments

  1. The really easy way: Change your permalink structure to include a “front” part. Eg. /news/%postname%

    The slightly more complicated and inflexible way: WordPress holds it’s data permastruct in a property of the global WP_Rewrite object stored in $wp_rewrite. You can hook in sometime early-ish (around init) and change this.

    <?php
    add_action('init', 'wpse39274_change_date');
    function wpse39274_change_date()
    {
        global $wp_rewrite;
        $wp_rewrite->date_structure = '/news/%year%/%monthnum%/%day%';
    }
    

    Inflexible because you’ve hard-coded the date base (news). This works fine, and if you don’t need the flexibility and want a quick fix, you should do this. Just be sure to flush your rewrite rules: visit Settings > Permalinks and hit save.

    The totally awesome, but a little bit complex way: Add a field to the permalinks options page where you can specify the date base.

    A class to wrap things up in.

    <?php
    class Custom_Date_Base
    {
        const SETTING = 'custom_date_base';
    
        private static $ins = null;
    
        public static function init()
        {
            add_action('plugins_loaded', array(self::instance(), '_setup'));
        }
    
        public static function instance()
        {
            is_null(self::$ins) && self::$ins = new self;
            return self::$ins;
        }
    
        public function _setup()
        {
            // we'll hook stuff in here later
        }
    }
    

    Now we need to hook into admin_init and use the settings API to add our field to the “Optional” section. We only need to use add_settings_field because Permalink options doesn’t actually use the settings API.

    <?php
    class Custom_Date_Base
    {
        const SETTING = 'custom_date_base';
    
        private static $ins = null;
    
        public static function init()
        {
            add_action('plugins_loaded', array(self::instance(), '_setup'));
        }
    
        public static function instance()
        {
            is_null(self::$ins) && self::$ins = new self;
            return self::$ins;
        }
    
        public function _setup()
        {
            add_action('admin_init', array($this, 'settings'));
        }
    
        public function settings()
        {
            add_settings_field(
                'custom-date-base',
                __('Date Base', 'custom-date-base'),
                array($this, 'field_cb'),
                'permalink',
                'optional',
                array('label_for' => self::SETTING)
            );
        }
    
        public function field_cb()
        {
            printf(
                '<input type="text" class="regular-text" id="%1$s" name="%1$s" value="%2$s" />',
                esc_attr(self::SETTING),
                esc_attr(get_option(self::SETTING))
            );
        }
    }
    

    We also need to hook into load-options-permalink.php to save stuff (due to the lack of settings API support).

    <?php
    class Custom_Date_Base
    {
        // snip snip
    
        public function _setup()
        {
            add_action('admin_init', array($this, 'settings'));
            add_action('load-options-permalink.php', array($this, 'save'));
            add_action('init', array($this, 'set_date_base'));
        }
    
        // snip snip
    
        // apparently options-permalink only halfways uses the settings api?
        public function save()
        {
            // make sure it's actually an update request.
            if('POST' != $_SERVER['REQUEST_METHOD'])
                return;
    
            // since this fires before the actual update stuff,
            // validate the permalink nonce.
            check_admin_referer('update-permalink');
    
            if(!empty($_POST[self::SETTING]))
            {
                update_option(
                    self::SETTING,
                    sanitize_title_with_dashes($_POST[self::SETTING])
                );
            }
            else
            {
                // remove it.
                delete_option(self::SETTING);
            }
        }
    }
    

    And finally hook into init and change the data permastruct. We can piggy-back on some build in validation that WordPress does by using WP_Rewrite::get_date_permastruct. Then it’s just a matter of some regex replacement.

    <?php
    class Custom_Date_Base
    {
        // snip snip
    
        public function _setup()
        {
            add_action('admin_init', array($this, 'settings'));
            add_action('load-options-permalink.php', array($this, 'save'));
            add_action('init', array($this, 'set_date_base'));
        }
    
        // snip snip
    
        public function set_date_base()
        {
            if($db = get_option(self::SETTING))
            {
                global $wp_rewrite;
    
                // current date permastruct
                $date_s = $wp_rewrite->get_date_permastruct();
    
                // get the "front" -- stuff before rewrite tags in post links
                $front = isset($wp_rewrite->front) ? $wp_rewrite->front : '/';
    
                // build some regex. We need to account for the global rewrite 
                // "front" as well as a possible "/date" that WP appends for
                // %post_id% permalink structure where the numbers of a Post ID
                // might conflict with with year/month/day numbers.
                $regex = '#^' . preg_quote($front, '#') . '(/date)?#ui';
    
                $wp_rewrite->date_structure = preg_replace($regex, "/{$db}/", $date_s);
    
                // apprently we need to make sure this happens?
                flush_rewrite_rules();
            }
        }
    }
    

    Here is the third option wrapped up in a plugin.