Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Recommended Plugins" input box #402

Merged
merged 28 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0d4cc39
Add Recommended Plugins input
mikachan Jun 19, 2023
3b8f937
Add Recommended Plugins section to theme readme
mikachan Jun 19, 2023
b2ed62c
Hide Recommended Plugins input on blank theme option
mikachan Jun 19, 2023
26ab37a
Merge branch 'trunk' into add/recommended-plugin-input
mikachan Jun 19, 2023
ffc9ab4
Update recommended plugins link
mikachan Jun 20, 2023
c12d7bb
Refactor readme logic
mikachan Jun 22, 2023
8f606cc
Fix file name reference in comment
mikachan Jun 22, 2023
2f6324a
Add recommended_plugins to React state
mikachan Jun 22, 2023
3e0a6e7
Handle recommended_plugins in API endpoints
mikachan Jun 22, 2023
66c0aac
Generate readme file on theme update
mikachan Jun 22, 2023
c3172d1
Handle readme file on theme update
mikachan Jun 22, 2023
a963e06
Increase spacing before image credits
mikachan Jun 22, 2023
903dbcd
Move image credits to end of readme
mikachan Jun 22, 2023
f74ccb4
Add additional check before running recommended_plugins_section
mikachan Jun 22, 2023
2dee0be
Remove recommended plugins input from create panel
mikachan Jun 22, 2023
15ce50e
Create separate update_readme_txt function
mikachan Jun 23, 2023
3a07203
Include updates to description, author and WP version in readme file …
mikachan Jun 23, 2023
64024f6
Adding readme file data to theme metadatda API
pbking Jun 23, 2023
49e86de
Default recommendedPlugins to empty string
mikachan Jun 23, 2023
cf8fe14
Use actual error message in failure response
mikachan Jun 23, 2023
e49038f
Remove extra line breaks from plugins section
mikachan Jun 23, 2023
8444ffb
Use correct success message
mikachan Jun 23, 2023
b0becb9
Move getThemeReadmeData into a useEffect
mikachan Jun 23, 2023
6c355f7
Default to returning empty object
mikachan Jun 23, 2023
1acb775
Add comment
mikachan Jun 23, 2023
5c6ca89
Fix extra line breaks being added to readme
mikachan Jun 23, 2023
1b293ab
Add placeholders to Recommended Plugin inputs
mikachan Jun 23, 2023
ac5a095
Small tweak to regex when replacing recommended plugins section to en…
pbking Jun 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 46 additions & 42 deletions admin/class-create-theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,17 @@ function create_sibling_theme( $theme, $screenshot ) {
$theme_slug = Theme_Utils::get_theme_slug( $theme['name'] );

// Sanitize inputs.
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['slug'] = $theme_slug;
$theme['template'] = wp_get_theme()->get( 'Template' );
$theme['text_domain'] = $theme_slug;
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['recommended_plugins'] = sanitize_textarea_field( $theme['recommended_plugins'] );
$theme['slug'] = $theme_slug;
$theme['template'] = wp_get_theme()->get( 'Template' );
$theme['text_domain'] = $theme_slug;

// Create ZIP file in the temporary directory.
$filename = tempnam( get_temp_dir(), $theme['slug'] );
Expand Down Expand Up @@ -164,17 +165,18 @@ function clone_theme( $theme, $screenshot ) {
$theme_slug = Theme_Utils::get_theme_slug( $theme['name'] );

// Sanitize inputs.
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['slug'] = $theme_slug;
$theme['template'] = '';
$theme['original_theme'] = wp_get_theme()->get( 'Name' );
$theme['text_domain'] = $theme_slug;
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['recommended_plugins'] = sanitize_textarea_field( $theme['recommended_plugins'] );
$theme['slug'] = $theme_slug;
$theme['template'] = '';
$theme['original_theme'] = wp_get_theme()->get( 'Name' );
$theme['text_domain'] = $theme_slug;

// Use previous theme's tags if custom tags are empty.
if ( empty( $theme['tags_custom'] ) ) {
Expand Down Expand Up @@ -235,17 +237,18 @@ function create_child_theme( $theme, $screenshot ) {
$child_theme_slug = Theme_Utils::get_theme_slug( $theme['name'] );

// Sanitize inputs.
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['is_parent_theme'] = true;
$theme['text_domain'] = $child_theme_slug;
$theme['template'] = $parent_theme_slug;
$theme['slug'] = $child_theme_slug;
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['recommended_plugins'] = sanitize_textarea_field( $theme['recommended_plugins'] );
$theme['is_parent_theme'] = true;
$theme['text_domain'] = $child_theme_slug;
$theme['template'] = $parent_theme_slug;
$theme['slug'] = $child_theme_slug;

// Create ZIP file in the temporary directory.
$filename = tempnam( get_temp_dir(), $theme['slug'] );
Expand Down Expand Up @@ -312,16 +315,17 @@ function create_blank_theme( $theme, $screenshot ) {
$theme_slug = Theme_Utils::get_theme_slug( $theme['name'] );

// Sanitize inputs.
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['template'] = '';
$theme['slug'] = $theme_slug;
$theme['text_domain'] = $theme_slug;
$theme['name'] = sanitize_text_field( $theme['name'] );
$theme['description'] = sanitize_text_field( $theme['description'] );
$theme['uri'] = sanitize_text_field( $theme['uri'] );
$theme['author'] = sanitize_text_field( $theme['author'] );
$theme['author_uri'] = sanitize_text_field( $theme['author_uri'] );
$theme['tags_custom'] = sanitize_text_field( $theme['tags_custom'] );
$theme['image_credits'] = sanitize_textarea_field( $theme['image_credits'] );
$theme['recommended_plugins'] = sanitize_textarea_field( $theme['recommended_plugins'] );
$theme['template'] = '';
$theme['slug'] = $theme_slug;
$theme['text_domain'] = $theme_slug;

// Create theme directory.
$source = plugin_dir_path( __DIR__ ) . 'assets/boilerplate';
Expand Down
16 changes: 15 additions & 1 deletion admin/create-theme/theme-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public static function create_admin_form_page() {
<input type="file" accept=".png" name="screenshot" id="screenshot" class="upload"/>
</label>
<br /><br />
<label id="image_credits_input">
<label class="hide-on-blank-theme">
<?php _e( 'Image Credits:', 'create-block-theme' ); ?><br />
<small><?php _e( 'List the credits for each image you have included in the theme. Include the image name, license type, and source URL.', 'create-block-theme' ); ?></small><br />
<small>
Expand All @@ -186,6 +186,20 @@ public static function create_admin_form_page() {
<textarea placeholder="<?php echo $image_credits_placeholder; ?>" rows="4" cols="50" name="theme[image_credits]" class="large-text"></textarea>
<br /><br />
</label>
<label class="hide-on-blank-theme">
<?php _e( 'Recommended Plugins:', 'create-block-theme' ); ?><br />
<small>
<?php
printf(
/* Translators: Recommended plugins link. */
esc_html__( 'List the recommended plugins for this theme. e.g. contact forms, social media. Plugins must be from the WordPress.org plugin repository (%s).', 'create-block-theme' ),
'<a href="' . esc_url( __( 'https://make.wordpress.org/themes/handbook/review/required/#6-plugins', 'create-block-theme' ) ) . '" target="_blank">read more</a>'
);
?>
</small><br />
<textarea rows="4" cols="50" name="theme[recommended_plugins]" class="large-text"></textarea>
<br /><br />
</label>
<div>
<?php Theme_Tags::theme_tags_section(); ?>
</div>
Expand Down
192 changes: 146 additions & 46 deletions admin/create-theme/theme-readme.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,28 @@ class Theme_Readme {
* Build a readme.txt file for CHILD/GRANDCHILD themes.
*/
public static function build_readme_txt( $theme ) {
$slug = $theme['slug'];
$name = $theme['name'];
$description = $theme['description'];
$uri = $theme['uri'];
$author = $theme['author'];
$author_uri = $theme['author_uri'];
$copy_year = gmdate( 'Y' );
$wp_version = get_bloginfo( 'version' );
$image_credits = $theme['image_credits'] ?? '';
$is_parent_theme = $theme['is_parent_theme'] ?? false;
$original_theme = $theme['original_theme'] ?? '';
$slug = $theme['slug'];
$name = $theme['name'];
$description = $theme['description'];
$uri = $theme['uri'];
$author = $theme['author'];
$author_uri = $theme['author_uri'];
$copy_year = gmdate( 'Y' );
$wp_version = get_bloginfo( 'version' );
$image_credits = $theme['image_credits'] ?? '';
$recommended_plugins = $theme['recommended_plugins'] ?? '';
$is_parent_theme = $theme['is_parent_theme'] ?? false;
$original_theme = $theme['original_theme'] ?? '';

// Handle copyright section.
$new_copyright_section = $is_parent_theme || $original_theme ? true : false;
$original_theme_credits = $new_copyright_section ? self::original_theme_credits( $name, $is_parent_theme ) : '';
$copyright_section = self::copyright_section( $new_copyright_section, $original_theme_credits, $name, $copy_year, $author, $image_credits );

$default_copyright_section = "== Copyright ==
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've refactored this and moved it lower down so that it's contained in copyright_section().


{$name} WordPress Theme, (C) {$copy_year} {$author}
{$name} is distributed under the terms of the GNU GPL.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.";

$copyright_section = $new_copyright_section ? self::copyright_section( $original_theme_credits, $image_credits ) : $default_copyright_section;
// Handle recommended plugins section.
if ( $recommended_plugins ) {
$recommended_plugins_section = self::recommended_plugins_section( $recommended_plugins );
}

return "=== {$name} ===
Contributors: {$author}
Expand All @@ -52,7 +44,7 @@ public static function build_readme_txt( $theme ) {

= 0.0.1 =
* Initial release

{$recommended_plugins_section}
{$copyright_section}
";
}
Expand Down Expand Up @@ -132,34 +124,142 @@ static function original_theme_credits( $new_name, $is_parent_theme = false ) {
*
* @return string
*/
static function copyright_section( $original_theme_credits, $image_credits ) {
$copyright_section = '';
$copyright_section_intro = '== Copyright ==';
static function copyright_section( $new_copyright_section, $original_theme_credits, $name, $copy_year, $author, $image_credits ) {
// Default copyright section.
$copyright_section = "== Copyright ==

{$name} WordPress Theme, (C) {$copy_year} {$author}
{$name} is distributed under the terms of the GNU GPL.

// Get current theme readme.txt
$current_readme = get_stylesheet_directory() . '/readme.txt' ?? '';
$current_readme_content = file_exists( $current_readme ) ? file_get_contents( $current_readme ) : '';
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

if ( ! $current_readme_content ) {
return;
}
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.";

// Copy copyright section from current theme readme.txt
if ( str_contains( $current_readme_content, $copyright_section_intro ) ) {
$copyright_section_start = strpos( $current_readme_content, $copyright_section_intro );
$copyright_section = substr( $current_readme_content, $copyright_section_start );
// If a new copyright section is required, then build ones based on the current theme.
if ( $new_copyright_section ) {
$copyright_section_intro = '== Copyright ==';

if ( $original_theme_credits ) {
$new_copyright_section = str_replace( $copyright_section_intro . "\n", '', $copyright_section );
$copyright_section = $copyright_section_intro . "\n\n" . $original_theme_credits . "\n" . $new_copyright_section;
// Get current theme readme.txt
$current_readme = get_stylesheet_directory() . '/readme.txt' ?? '';
$current_readme_content = file_exists( $current_readme ) ? file_get_contents( $current_readme ) : '';

if ( ! $current_readme_content ) {
return;
}

if ( $image_credits ) {
$copyright_section = $copyright_section . "\n" . $image_credits;
// Copy copyright section from current theme readme.txt
if ( str_contains( $current_readme_content, $copyright_section_intro ) ) {
$copyright_section_start = strpos( $current_readme_content, $copyright_section_intro );
$copyright_section = substr( $current_readme_content, $copyright_section_start );

if ( $original_theme_credits ) {
$new_copyright_section = str_replace( $copyright_section_intro . "\n", '', $copyright_section );
$copyright_section = $copyright_section_intro . "\n\n" . $original_theme_credits . "\n" . $new_copyright_section;
}
}
}

if ( $image_credits ) {
$copyright_section = $copyright_section . "\n" . $image_credits;
}

return $copyright_section;
}

/**
* Build Recommended Plugins section.
*
* @return string
*/
static function recommended_plugins_section( $recommended_plugins, $updated_readme = '' ) {
$recommended_plugins_section = '';

if ( ! $recommended_plugins ) {
return '';
}

$section_start = '
== Recommended Plugins ==

The following plugins are recommended for use with this theme:';
$section_end = "(End of Recommended Plugins)\n";

// Remove existing Recommended Plugins section.
if ( $updated_readme && str_contains( $updated_readme, $section_start ) ) {
$pattern = '/(' . preg_quote( $section_start, '/' ) . ')(.*?)((' . preg_quote( $section_end, '/' ) . ')|$)/s';
preg_match_all( $pattern, $updated_readme, $matches );
$current_section = $matches[0][0];
$updated_readme = str_replace( $current_section, '', $updated_readme );
}

$recommended_plugins_section = $section_start . "\n\n" . $recommended_plugins . "\n\n" . $section_end;

if ( $updated_readme ) {
return $updated_readme . $recommended_plugins_section;
}

return $recommended_plugins_section;
}

/**
* Update current readme.txt file, rather than building a new one.
*
* @return string
*/
public static function update_readme_txt( $theme ) {
$description = $theme['description'];
$author = $theme['author'];
$wp_version = get_bloginfo( 'version' );
$image_credits = $theme['image_credits'] ?? '';
$recommended_plugins = $theme['recommended_plugins'] ?? '';
$updated_readme = '';
$current_readme = get_stylesheet_directory() . '/readme.txt' ?? '';
$readme_content = file_exists( $current_readme ) ? file_get_contents( $current_readme ) : '';

if ( ! $readme_content ) {
return;
}

$updated_readme = $readme_content;

// Update description.
if ( $description ) {
$pattern = '/(== Description ==)(.*?)(\n\n=|$)/s';
preg_match_all( $pattern, $updated_readme, $matches );
$current_description = $matches[0][0];
$updated_readme = str_replace( $current_description, "== Description ==\n\n{$description}\n\n=", $updated_readme );
}

// Update Author/Contributors.
if ( $author ) {
$pattern = '/(Contributors:)(.*?)(\n|$)/s';
preg_match_all( $pattern, $updated_readme, $matches );
$current_uri = $matches[0][0];
$updated_readme = str_replace( $current_uri, "Contributors: {$author}\n", $updated_readme );
}

// Update "Tested up to" version.
if ( $wp_version ) {
$pattern = '/(Tested up to:)(.*?)(\n|$)/s';
preg_match_all( $pattern, $updated_readme, $matches );
$current_uri = $matches[0][0];
$updated_readme = str_replace( $current_uri, "Tested up to: {$wp_version}\n", $updated_readme );
}

if ( $recommended_plugins ) {
$updated_readme = self::recommended_plugins_section( $recommended_plugins, $updated_readme );
}

if ( $image_credits ) {
$updated_readme = $updated_readme . "\n\n" . $image_credits;
}

return $updated_readme;
}
}
2 changes: 1 addition & 1 deletion admin/create-theme/theme-tags.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class Theme_Tags {
/**
* Build theme tags list for readme.txt.
* Build theme tags list for style.css.
*
* @param array $theme Theme data.
* @return string
Expand Down
Loading