Conversation
Replace short array syntax Remove the readme.txt file from class-file-check.php Update the error message when the file is missing.
|
Thank you. |
|
Test with a theme that is missing a readme.txt and readme.md Confirm that the error about the missing readme is displaying. Test with a theme with missing headers in the readme. Confirm that the warnings are displaying. Test with a theme with incorrect headers in the readme. my readme header is like below, Confirm that the warnings are displaying. On a side note, is this INFO necessary? |
|
The requires at least is compared to |
|
The info does make it noisy. My thought was to: But if you prefer it can be removed and reconsidered once there are solid plans to show it in the directory. |
|
Yeah I think it is broken. I'd like to compare with the live plugin validator. |
|
Looks good.
|
|
protected $latest_wordpress_version = '5.8'; We need to make it dynamic. |
|
When I added 2 users without “,” comma between them, the check returned no error.
|
|
I have not used the sniffer for so long, that I forgot that it checks for this: |
But how? |
Thanks for the link. I got the contributor validation working based on the sniffer. It’s silly but I don’t know how to create a branch off a branch. Any suggestions on how to proceed. |
Co-authored-by: Dion Hulse <dion@wordpress.org>
|
@dd32 What will happen if my local WordPress version is less than the current version? |
|
No notice is shown in this case, But if we go above If the WordPress version will be higher than 5.9, then do we need to reset the version again? Nothing shows for, Rest of the things looks fine to me. |
We would have had to but Dion's update solves that. |
Okay, thanks for the update. Any idea how to fix the readme issues with spacing? |
I am not sure either 😊 Maybe we need to do it in two steps and merge this one first? |
I'll see if I can make it remove blank lines from the header, but the warning is also correct, the blank line must not be there. |
Check if the name in the readme matches the theme name, if not, error. Update the $latest_wordpres_version variable. Remove empty lines to prevent errors with the check.
|
8e696d2 Checks if the name in the readme matches the theme name, if not, error. To avoid reading the wrong readme file if there is more than one readme, this PR needs to be tested together with |
|
Does the license and license URI have a single space after the colon? |
|
Requires at least: 5.5 Tested with both adding space, removing space, double space. The result is same. |
Sync branch with master
|
I think I found the bug where it does not show that the license is missing, but I need your full readme file to confirm. It is not only checking the file header, so if the words "License: blah blah" are elsewhere in the readme file, like for an asset, it will use that. |
Try to solve timeout issues. Check for uppercase file names as well as lowercase with stripos.
There was a problem hiding this comment.
Pull request overview
Adds a dedicated readme validator for themes to ensure a theme-root readme.txt/readme.md is present and to validate key readme headers, addressing false positives caused by third-party readmes in subfolders (issue #375).
Changes:
- Introduces a
Readme_Checkto locate and validate a theme’s readme file and required headers. - Adds a
Readme_Parserto extract theme name and key header fields from the readme. - Removes
readme.txtfrom the generic “must-have files” list so readme validation is handled by the dedicated check.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| checks/class-readme-parser.php | New parser for extracting readme title + header values (Requires/Tested/PHP/etc.). |
| checks/class-readme-check.php | New theme check that finds the theme-root readme and emits required/warning/info notices. |
| checks/class-file-check.php | Stops treating readme.txt as a mandatory file (delegates to the new readme check). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| protected function sanitize_requires_version( $version ) { | ||
| $version = trim( $version ); | ||
| $latest_wordpress_version = '5.9'; | ||
|
|
||
| if ( $version ) { | ||
| // Handle the edge-case of 'WordPress 5.0' and 'WP 5.0' for historical purposes. | ||
| $strip_phrases = array( 'WordPress', 'WP', 'or higher', 'and above', '+' ); | ||
| $version = trim( str_ireplace( $strip_phrases, '', $version ) ); | ||
|
|
||
| // Strip off any -alpha, -RC, -beta suffixes, as these complicate comparisons and are rarely used. | ||
| list( $version, ) = explode( '-', $version ); | ||
|
|
||
| if ( | ||
| // x.y or x.y.z | ||
| ! preg_match( '!^\d+\.\d(\.\d+)?$!', $version ) || | ||
| // Allow themes to mark themselves as requireing Stable+0.1 (trunk/master) but not higher | ||
| $latest_wordpress_version && ( (float) $version > (float) $latest_wordpress_version + 0.1 ) | ||
| ) { | ||
| $this->warnings['requires_header_ignored'] = true; |
| foreach ( $contents as $i => $line ) { | ||
| $contents[ $i ] = mb_convert_encoding( $line, 'UTF-8', 'UTF-16' ); |
| /** | ||
| * Warning flags which indicate specific parsing failures have occured. | ||
| * | ||
| * @var array | ||
| */ | ||
| public $warnings = array(); |
| /** | ||
| * Sanitizes the Requires at least header to ensure that it's a valid version header | ||
| * | ||
| * @param string $version The minim required WordPress version. |
| if ( | ||
| // x.y or x.y.z | ||
| ! preg_match( '!^\d+\.\d(\.\d+)?$!', $version ) || | ||
| // Allow themes to mark themselves as requireing Stable+0.1 (trunk/master) but not higher |
| public function check( $php_files, $css_files, $other_files ) { | ||
|
|
||
| /** | ||
| * Latest WordPress version | ||
| * | ||
| * @var string $latest_wordpress_version | ||
| */ | ||
| if ( defined( 'WP_CORE_LATEST_RELEASE' ) ) { | ||
| // When running on WordPress.org, this constant defines the latest WordPress release. | ||
| $latest_wordpress_version = WP_CORE_LATEST_RELEASE; | ||
| } else { | ||
| // Assume that the local environment being tested in is up to date. | ||
| $latest_wordpress_version = $GLOBALS['wp_version']; | ||
| } | ||
|
|
||
| checkcount(); | ||
|
|
||
| // Get a list of file names and check for the readme. | ||
| $readme = ''; | ||
|
|
||
| // Get the contents of themeslug/filename: | ||
| foreach ( $other_files as $path => $contents ) { | ||
| if ( stripos( $path, $this->slug . '/readme.txt' ) || stripos( $path, $this->slug . '/readme.md' ) !== false ) { | ||
| $readme .= $contents; | ||
| } | ||
| } | ||
|
|
||
| // Publish an error if there is no readme file. | ||
| if ( empty( $readme ) ) { | ||
| $this->error[] = sprintf( | ||
| '<span class="tc-lead tc-required">%s</span>: %s', | ||
| __( 'REQUIRED', 'theme-check' ), | ||
| __( 'The readme file is missing.', 'theme-check' ) | ||
| ); | ||
| $ret = false; | ||
| } else { |
| // Error if the theme name is missing in the readme. | ||
| if ( empty( $readme->name ) ) { | ||
| $this->error[] = sprintf( | ||
| '<span class="tc-lead tc-required">%s</span>: %s', | ||
| __( 'README ERROR', 'theme-check' ), | ||
| /* translators: 1: 'Theme Name' section title, 2: 'Theme Name' */ | ||
| sprintf( | ||
| __( 'Could not find a theme name in the readme. Theme name format looks like: %1$s. Please change %2$s to reflect the actual name of your theme.', 'theme-check' ), | ||
| '<code>=== Theme Name ===</code>', | ||
| '<code>Theme Name</code>' | ||
| ) | ||
| ); | ||
| $ret = false; | ||
| } elseif ( $readme->name != $this->theme ) { | ||
| $this->error[] = sprintf( | ||
| '<span class="tc-lead tc-required">%s</span>: %s', | ||
| __( 'README ERROR', 'theme-check' ), | ||
| /* translators: 1: actual theme name, 2: theme name in readme, 3: 'Theme Name' section title, 4: 'Theme Name' */ | ||
| sprintf( | ||
| __( 'The theme name in the readme %1$s does not match the name of your theme %2$s. Theme name format looks like: %3$s. Please change %4$s to reflect the actual name of your theme.', 'theme-check' ), | ||
| '<code>' . esc_html( $readme->name ) . '</code>', | ||
| '<code>' . esc_html( $this->theme ) . '</code>', | ||
| '<code>=== Theme Name ===</code>', | ||
| '<code>Theme Name</code>' | ||
| ) |
| if ( empty( $readme->sections['description'] ) ) { | ||
| $this->error[] = sprintf( | ||
| '<span class="tc-lead tc-info ">%s</span>: %s', | ||
| __( 'README INFO', 'theme-check' ), | ||
| sprintf( | ||
| /* translators: %s: section title */ | ||
| __( 'No %s section was found in the readme.', 'theme-check' ), | ||
| '<code>== Description ==</code>' | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| if ( empty( $readme->sections['faq'] ) ) { | ||
| $this->error[] = sprintf( | ||
| '<span class="tc-lead tc-info ">%s</span>: %s', | ||
| __( 'README INFO', 'theme-check' ), | ||
| sprintf( | ||
| /* translators: %s: section title */ | ||
| __( 'No %s section was found in the readme.', 'theme-check' ), | ||
| '<code>== Frequently Asked Questions ==</code>' | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| if ( empty( $readme->sections['changelog'] ) ) { | ||
| $this->error[] = sprintf( | ||
| '<span class="tc-lead tc-info ">%s</span>: %s', | ||
| __( 'README INFO', 'theme-check' ), | ||
| sprintf( | ||
| /* translators: %s: section title */ | ||
| __( 'No %s section was found in the readme.', 'theme-check' ), | ||
| '<code>== Changelog ==</code>' | ||
| ) | ||
| ); |










Fixes #375
This check and the accompanying parser is copied from the plugin readme validator.
It is more limited than the plugin readme validator, and it does not work for themes that are in sub folders.
The subfolder issue may be solved by #370. Untested.
How to test: