diff --git a/src/wp-admin/options-permalink.php b/src/wp-admin/options-permalink.php
index 6fab4d2143..78b8d49dde 100644
--- a/src/wp-admin/options-permalink.php
+++ b/src/wp-admin/options-permalink.php
@@ -82,6 +82,9 @@ if ( isset($_POST['permalink_structure']) || isset($_POST['category_base']) ) {
else
$permalink_structure = $blog_prefix . $permalink_structure;
}
+
+ $permalink_structure = sanitize_option( 'permalink_structure', $permalink_structure );
+
$wp_rewrite->set_permalink_structure( $permalink_structure );
}
@@ -99,6 +102,24 @@ if ( isset($_POST['permalink_structure']) || isset($_POST['category_base']) ) {
$wp_rewrite->set_tag_base( $tag_base );
}
+ $message = __( 'Permalink structure updated.' );
+
+ if ( $iis7_permalinks ) {
+ if ( $permalink_structure && ! $usingpi && ! $writable ) {
+ $message = __( 'You should update your web.config now.' );
+ } elseif ( $permalink_structure && ! $usingpi && $writable ) {
+ $message = __( 'Permalink structure updated. Remove write access on web.config file now!' );
+ }
+ } elseif ( ! $is_nginx && $permalink_structure && ! $usingpi && ! $writable && $update_required ) {
+ $message = __( 'You should update your .htaccess now.' );
+ }
+
+ if ( ! get_settings_errors() ) {
+ add_settings_error( 'general', 'settings_updated', $message, 'updated' );
+ }
+
+ set_transient( 'settings_errors', get_settings_errors(), 30 );
+
wp_redirect( admin_url( 'options-permalink.php?settings-updated=true' ) );
exit;
}
@@ -125,42 +146,12 @@ if ( $iis7_permalinks ) {
}
}
-if ( $wp_rewrite->using_index_permalinks() )
- $usingpi = true;
-else
- $usingpi = false;
+$usingpi = $wp_rewrite->using_index_permalinks();
flush_rewrite_rules();
require( ABSPATH . 'wp-admin/admin-header.php' );
-
-if ( ! empty( $_GET['settings-updated'] ) ) : ?>
-
diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php
index 4f632eef9a..46d9a9068a 100644
--- a/src/wp-includes/formatting.php
+++ b/src/wp-includes/formatting.php
@@ -4204,6 +4204,14 @@ function sanitize_option( $option, $value ) {
$value = esc_url_raw( $value );
$value = str_replace( 'http://', '', $value );
}
+
+ if ( 'permalink_structure' === $option && '' !== $value && ! preg_match( '/%[^\/%]+%/', $value ) ) {
+ $error = sprintf(
+ /* translators: %s: Codex URL */
+ __( 'A structure tag is required when using custom permalinks.
Learn more' ),
+ __( 'https://codex.wordpress.org/Using_Permalinks#Choosing_your_permalink_structure' )
+ );
+ }
break;
case 'default_role' :
diff --git a/tests/phpunit/tests/option/sanitize-option.php b/tests/phpunit/tests/option/sanitize-option.php
index 8efa985b00..bb4a814c54 100644
--- a/tests/phpunit/tests/option/sanitize-option.php
+++ b/tests/phpunit/tests/option/sanitize-option.php
@@ -119,4 +119,42 @@ class Tests_Sanitize_Option extends WP_UnitTestCase {
$this->assertSame( $expected, sanitize_option( 'blogname', $value ) );
$this->assertSame( $expected, sanitize_option( 'blogdescription', $value ) );
}
+
+ /**
+ * @dataProvider permalink_structure_provider
+ */
+ public function test_sanitize_permalink_structure( $provided, $expected, $valid ) {
+ global $wp_settings_errors;
+
+ $old_wp_settings_errors = (array) $wp_settings_errors;
+
+ $actual = sanitize_option( 'permalink_structure', $provided);
+ $errors = get_settings_errors( 'permalink_structure' );
+
+ // Clear errors.
+ $wp_settings_errors = $old_wp_settings_errors;
+
+ if ( $valid ) {
+ $this->assertEmpty( $errors );
+ } else {
+ $this->assertNotEmpty( $errors );
+ $this->assertEquals( 'invalid_permalink_structure', $errors[0]['code'] );
+ }
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function permalink_structure_provider() {
+ return array(
+ array( '', '', true ),
+ array( '%postname', false, false ),
+ array( '%/%', false, false ),
+ array( '%%%', false, false ),
+ array( '%a%', '%a%', true ),
+ array( '%postname%', '%postname%', true ),
+ array( '/%postname%/', '/%postname%/', true ),
+ array( '/%year%/%monthnum%/%day%/%postname%/', '/%year%/%monthnum%/%day%/%postname%/', true ),
+ array( '/%year/%postname%/', '/%year/%postname%/', true ),
+ );
+ }
}