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.