Using plugin code to modify the permalink settings of a WordPress blog is surprisingly not straight forward. The options involved (of which their are three), need to be modified in three places: the option values themselves, the rewrite rules in the WordPress database, and the .htaccess (or equivalent) files on disk. Update just one, and it won’t work.
Looking for a solution to this problem, I pulled out a chunk of code from wp-admin/options-permalink.php. After a few small modifications I ended up with the following function:
function modify_permalinks($permalink_structure, $category_base, $tag_base){
global $wp_rewrite;
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/misc.php');
# get paths
$home_path = get_home_path();
$iis7_permalinks = iis7_supports_permalinks();
# set the structure
$permalink_structure = preg_replace('#/+#', '/', '/' . $permalink_structure);
$wp_rewrite->set_permalink_structure($permalink_structure);
$category_base = preg_replace('#/+#', '/', '/' . $category_base);
$wp_rewrite->set_category_base($category_base);
$tag_base = preg_replace('#/+#', '/', '/' . $tag_base);
$wp_rewrite->set_tag_base($tag_base);
# check if there is a file to rewrite
if ( $iis7_permalinks ) {
if ( ( ! file_exists($home_path . 'web.config') && win_is_writable($home_path) ) || win_is_writable($home_path . 'web.config') )
$writable = true;
else
$writable = false;
} else {
if ( ( ! file_exists($home_path . '.htaccess') && is_writable($home_path) ) || is_writable($home_path . '.htaccess') )
$writable = true;
else
$writable = false;
}
# flush the rules
update_option('rewrite_rules', FALSE);
$wp_rewrite->flush_rules($writable);
}
So far it seems to work with any action hook in both WordPress and WordPress MU (durring registration, when modifying an option, etc.), but I haven’t tried everything.