diff --git a/public_html/wp-content/plugins/pattern-directory/includes/pattern-validation.php b/public_html/wp-content/plugins/pattern-directory/includes/pattern-validation.php
index 20a7c345..a0ab4f7f 100644
--- a/public_html/wp-content/plugins/pattern-directory/includes/pattern-validation.php
+++ b/public_html/wp-content/plugins/pattern-directory/includes/pattern-validation.php
@@ -687,10 +687,11 @@ function validate_title( $prepared_post, $request ) {
);
}
- if ( ! is_title_valid( $title ) ) {
+ $title_error = get_title_error( $title );
+ if ( $title_error ) {
return new \WP_Error(
'rest_pattern_invalid_title',
- __( 'Pattern title is invalid. The pattern title should describe the pattern.', 'wporg-patterns' ),
+ $title_error,
array( 'status' => 400 )
);
}
@@ -1120,33 +1121,33 @@ function check_for_spam( $post ) {
}
/**
- * Helper function to check for a valid pattern title.
+ * Explain why a pattern title is invalid, so the author knows what to change.
*
* @param string $title Pattern title.
- * @return boolean
+ * @return string The reason the title is invalid, or an empty string if it's valid.
*/
-function is_title_valid( $title ) {
+function get_title_error( $title ) {
if ( strip_shortcodes( $title ) !== $title || wp_strip_all_tags( $title ) !== $title ) {
- return false;
+ return __( 'Pattern titles cannot contain HTML or shortcodes.', 'wporg-patterns' );
}
if ( content_has_block_directives( $title ) ) {
- return false;
+ return __( 'Pattern titles cannot contain interactivity directives.', 'wporg-patterns' );
}
- // Check title against a list of disallowed words.
- // Note the space after `test ` to avoid matching "testimonial".
- $disallow_list = array( 'test ', 'testing', 'my pattern', 'wordpress', 'example' );
-
- if ( 'test' === strtolower( $title ) ) {
- return false;
- }
+ // Whole words only, so "Latest Posts" and "Testimonial" are fine.
+ $disallow_list = array( 'test', 'testing', 'my pattern', 'my patterns', 'wordpress', 'example' );
foreach ( $disallow_list as $disallowed ) {
- if ( false !== stripos( $title, $disallowed ) ) {
- return false;
+ $pattern = '/\b' . str_replace( ' ', '\s+', preg_quote( $disallowed, '/' ) ) . '\b/iu';
+ if ( preg_match( $pattern, $title, $matches ) ) {
+ return sprintf(
+ /* translators: %s: The word from the title that isn't allowed, e.g. "test". */
+ __( 'Pattern titles cannot include "%s". The title should describe the pattern.', 'wporg-patterns' ),
+ $matches[0]
+ );
}
}
- return true;
+ return '';
}
diff --git a/public_html/wp-content/plugins/pattern-directory/tests/phpunit/pattern-title-validation-test.php b/public_html/wp-content/plugins/pattern-directory/tests/phpunit/pattern-title-validation-test.php
index d1095243..94fbc860 100644
--- a/public_html/wp-content/plugins/pattern-directory/tests/phpunit/pattern-title-validation-test.php
+++ b/public_html/wp-content/plugins/pattern-directory/tests/phpunit/pattern-title-validation-test.php
@@ -84,6 +84,16 @@ public function data_valid_title() {
array(
array_merge( $defaults, array( 'title' => 'Testimonial' ) ),
),
+ // Disallowed words inside other words.
+ array(
+ array_merge( $defaults, array( 'title' => 'Latest Posts' ) ),
+ ),
+ array(
+ array_merge( $defaults, array( 'title' => 'Contest Banner' ) ),
+ ),
+ array(
+ array_merge( $defaults, array( 'title' => 'Examples Grid' ) ),
+ ),
array(
array(
'title' => '',
@@ -178,6 +188,49 @@ public function data_invalid_title() {
);
}
+ /**
+ * Test that the error says why the title is invalid.
+ *
+ * @dataProvider data_invalid_title_message
+ *
+ * @param string $title Submitted title.
+ * @param string $expected_message Expected error message.
+ */
+ public function test_invalid_title_message( $title, $expected_message ) {
+ wp_set_current_user( self::$user );
+
+ $request = new WP_REST_Request( 'POST', '/wp/v2/wporg-pattern/' . self::$pattern_id );
+ $request->set_header( 'content-type', 'application/json' );
+ $request->set_body(
+ wp_json_encode(
+ array(
+ 'title' => $title,
+ 'status' => 'publish',
+ 'content' => self::$valid_content,
+ )
+ )
+ );
+
+ $data = rest_do_request( $request )->get_data();
+ $this->assertSame( 'rest_pattern_invalid_title', $data['code'] );
+ $this->assertSame( $expected_message, $data['message'] );
+ }
+
+ /**
+ * Data provider for the invalid title messages.
+ *
+ * @return array
+ */
+ public function data_invalid_title_message() {
+ return array(
+ array( 'Test Pattern', 'Pattern titles cannot include "Test". The title should describe the pattern.' ),
+ array( 'My Pattern', 'Pattern titles cannot include "My Pattern". The title should describe the pattern.' ),
+ array( 'My Patterns', 'Pattern titles cannot include "My Patterns". The title should describe the pattern.' ),
+ array( 'WordPress Header', 'Pattern titles cannot include "WordPress". The title should describe the pattern.' ),
+ array( 'Quote markup', 'Pattern titles cannot contain HTML or shortcodes.' ),
+ );
+ }
+
/**
* Test invalid pattern title: Published pattern, has empty title with no new title.
*/