This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,346 @@
<?php
/**
* Plugin Name: Child Theme Wizard
* Plugin URI: https://wpguru.tv
* Description: Creates a child theme from any installed parent theme.
* Version: 1.5
* Author: Jay Versluis
* Author URI: https://wpguru.tv
* License: GPL2
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: child-theme-wizard
*/
/* Copyright 2013-2026 Jay Versluis (email support@wpguru.tv)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'admin_menu', 'ctw_menu' );
function ctw_menu(): void {
add_submenu_page(
'tools.php',
__( 'Child Theme Wizard', 'child-theme-wizard' ),
__( 'Child Theme Wizard', 'child-theme-wizard' ),
'manage_options',
'ChildThemeWizard',
'ctw_main_function'
);
}
function ctw_main_function(): void {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient privileges to access this page.', 'child-theme-wizard' ) );
}
?>
<div class="wrap">
<h1><?php esc_html_e( 'Child Theme Wizard', 'child-theme-wizard' ); ?></h1>
<?php
if ( isset( $_POST['hiddenfield'] ) && $_POST['hiddenfield'] === 'Y' ) {
// Verify nonce — blocks CSRF attacks.
check_admin_referer( 'ctw_create_child_theme', 'ctw_nonce' );
// Validate parent against actually-installed parent themes.
$parent_themes = ctw_giveme_parents();
$valid_parents = array_map( fn( $t ) => $t->get_stylesheet(), $parent_themes );
$submitted_parent = sanitize_text_field( wp_unslash( $_POST['parent'] ?? '' ) );
if ( ! in_array( $submitted_parent, $valid_parents, true ) ) {
wp_die( esc_html__( 'Invalid parent theme selected.', 'child-theme-wizard' ) );
}
$newchildtheme = array(
'parent' => $submitted_parent,
'title' => sanitize_text_field( wp_unslash( $_POST['title'] ?? '' ) ),
'description' => sanitize_text_field( wp_unslash( $_POST['description'] ?? '' ) ),
'url' => esc_url_raw( wp_unslash( $_POST['url'] ?? '' ) ),
'author' => sanitize_text_field( wp_unslash( $_POST['author'] ?? '' ) ),
'author-url' => esc_url_raw( wp_unslash( $_POST['author-url'] ?? '' ) ),
'version' => sanitize_text_field( wp_unslash( $_POST['version'] ?? '' ) ),
'include-gpl' => ( isset( $_POST['include-gpl'] ) && $_POST['include-gpl'] === 'on' ) ? 'on' : 'off',
);
$status = ctw_create_theme( $newchildtheme );
if ( $status['alert'] === -1 ) {
?>
<div class="notice notice-error">
<p><strong><?php esc_html_e( 'Yikes — something went wrong:', 'child-theme-wizard' ); ?></strong></p>
<?php echo wp_kses_post( $status['message'] ); ?>
</div>
<p><a href="<?php echo esc_url( admin_url( 'tools.php?page=ChildThemeWizard' ) ); ?>"><?php esc_html_e( 'Try again?', 'child-theme-wizard' ); ?></a></p>
<?php
} else {
?>
<div class="notice notice-success">
<?php echo wp_kses_post( $status['message'] ); ?>
<p><strong><?php esc_html_e( 'Your Child Theme was created successfully!', 'child-theme-wizard' ); ?></strong></p>
</div>
<p>
<?php
printf(
/* translators: 1: link to Appearance > Themes, 2: link to Appearance > Editor */
esc_html__( 'Head over to %1$s to activate it. Add your custom styles in %2$s.', 'child-theme-wizard' ),
'<a href="' . esc_url( admin_url( 'themes.php' ) ) . '">' . esc_html__( 'Appearance Themes', 'child-theme-wizard' ) . '</a>',
'<a href="' . esc_url( admin_url( 'theme-editor.php' ) ) . '">' . esc_html__( 'Appearance Editor', 'child-theme-wizard' ) . '</a>'
);
?>
</p>
<?php
}
} else {
$current_user = wp_get_current_user();
$parent_themes = ctw_giveme_parents();
$current_theme = wp_get_theme();
?>
<p>
<?php
printf(
/* translators: %s: link to WordPress child theme documentation */
esc_html__( 'This simple wizard will help you generate a new %s with just one click.', 'child-theme-wizard' ),
'<a href="https://developer.wordpress.org/themes/advanced-topics/child-themes/" target="_blank">' . esc_html__( 'Child Theme', 'child-theme-wizard' ) . '</a>'
);
?>
</p>
<p><?php esc_html_e( 'Select which theme you want to use as a base, fill in the details and click "Create Child Theme".', 'child-theme-wizard' ); ?></p>
<hr>
<form name="ctwform" method="post" action="">
<?php wp_nonce_field( 'ctw_create_child_theme', 'ctw_nonce' ); ?>
<input type="hidden" name="hiddenfield" value="Y">
<table class="form-table" role="presentation">
<tr>
<th scope="row"><label for="ctw-parent"><?php esc_html_e( 'Parent Theme', 'child-theme-wizard' ); ?></label></th>
<td>
<select name="parent" id="ctw-parent">
<?php foreach ( $parent_themes as $theme ) :
$stylesheet = $theme->get_stylesheet();
$name = $theme->get( 'Name' );
$is_active = $current_theme->get( 'Name' ) === $name;
?>
<option value="<?php echo esc_attr( $stylesheet ); ?>"<?php selected( $is_active ); ?>>
<?php
echo esc_html( $name );
if ( $is_active ) {
echo ' (' . esc_html__( 'currently active', 'child-theme-wizard' ) . ')';
}
?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr>
<th scope="row"><label for="ctw-title"><?php esc_html_e( 'Title', 'child-theme-wizard' ); ?></label></th>
<td>
<input type="text" name="title" id="ctw-title" value="" class="regular-text">
<p class="description"><?php esc_html_e( "What's your new Child Theme called?", 'child-theme-wizard' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="ctw-description"><?php esc_html_e( 'Description', 'child-theme-wizard' ); ?></label></th>
<td>
<input type="text" name="description" id="ctw-description" value="" class="regular-text">
<p class="description"><?php esc_html_e( 'A few notes about your Child Theme.', 'child-theme-wizard' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="ctw-url"><?php esc_html_e( 'Child Theme URL', 'child-theme-wizard' ); ?></label></th>
<td>
<input type="url" name="url" id="ctw-url" value="" class="regular-text">
<p class="description"><?php esc_html_e( 'Does it have a website or release post?', 'child-theme-wizard' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="ctw-author"><?php esc_html_e( 'Author', 'child-theme-wizard' ); ?></label></th>
<td>
<input type="text" name="author" id="ctw-author" value="<?php echo esc_attr( $current_user->display_name ); ?>" class="regular-text">
<p class="description"><?php esc_html_e( "That's you.", 'child-theme-wizard' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="ctw-author-url"><?php esc_html_e( 'Author URL', 'child-theme-wizard' ); ?></label></th>
<td>
<input type="url" name="author-url" id="ctw-author-url" value="<?php echo esc_url( $current_user->user_url ); ?>" class="regular-text">
<p class="description"><?php esc_html_e( "That's your website.", 'child-theme-wizard' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="ctw-version"><?php esc_html_e( 'Version', 'child-theme-wizard' ); ?></label></th>
<td>
<input type="text" name="version" id="ctw-version" value="1.0" class="small-text">
<p class="description"><?php esc_html_e( 'Start with 1.0 and work your way up.', 'child-theme-wizard' ); ?></p>
</td>
</tr>
<tr>
<th scope="row"><label for="ctw-include-gpl"><?php esc_html_e( 'Include GPL License', 'child-theme-wizard' ); ?></label></th>
<td>
<select name="include-gpl" id="ctw-include-gpl">
<option value="on"><?php esc_html_e( 'Yes Please!', 'child-theme-wizard' ); ?></option>
<option value="off"><?php esc_html_e( 'No Thanks', 'child-theme-wizard' ); ?></option>
</select>
</td>
</tr>
</table>
<p class="submit">
<input type="submit" name="Submit" class="button-primary" value="<?php esc_attr_e( 'Create Child Theme', 'child-theme-wizard' ); ?>">
</p>
</form>
<?php
}
?>
<br><hr><br>
</div><!-- .wrap -->
<p><a href="https://wpguru.co.uk" target="_blank"><img src="<?php echo esc_url( plugins_url( 'images/guru-header-2013.png', __FILE__ ) ); ?>" width="300" alt="WP Guru"></a></p>
<p>
<a href="https://wpguru.co.uk/2014/03/introducing-child-theme-wizard-for-wordpress/" target="_blank">Plugin by Jay Versluis</a>
| <a href="https://github.com/versluis/Child-Theme-Wizard" target="_blank">Fork me or Contribute on GitHub</a>
| <a href="https://patreon.com/versluis" target="_blank">Support me on Patreon</a>
</p>
<?php
}
function ctw_create_theme( array $childtheme ): array {
$status = array(
'alert' => 0,
'message' => '',
);
global $wp_filesystem;
if ( empty( $wp_filesystem ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
WP_Filesystem();
}
$directory = get_theme_root() . '/' . sanitize_file_name( $childtheme['title'] );
if ( ! $wp_filesystem->mkdir( $directory ) ) {
$status['message'] = '<p>' . esc_html__( 'Could not create directory. Does it exist already?', 'child-theme-wizard' ) . '</p>';
$status['alert'] = -1;
return $status;
}
$status['message'] .= '<p>' . esc_html__( 'Directory created successfully.', 'child-theme-wizard' ) . '</p>';
// Strip */ so user-supplied values cannot break out of the CSS comment block.
$safe = array_map( fn( $v ) => str_replace( '*/', '', (string) $v ), $childtheme );
$style = "/* \n Theme Name: " . $safe['title'];
$style .= "\n Theme URI: " . $safe['url'];
$style .= "\n Description: " . $safe['description'];
$style .= "\n Author: " . $safe['author'];
$style .= "\n Author URI: " . $safe['author-url'];
$style .= "\n Template: " . $safe['parent'];
$style .= "\n Version: " . $safe['version'];
if ( $safe['include-gpl'] === 'on' ) {
$style .= "\n License: GNU General Public License v2 or later";
$style .= "\n License URI: http://www.gnu.org/licenses/gpl-2.0.html";
}
$style .= "\n\n /* == Add your own styles below this line ==";
$style .= "\n--------------------------------------------*/\n\n";
if ( ! $wp_filesystem->put_contents( $directory . '/style.css', $style, FS_CHMOD_FILE ) ) {
$status['message'] .= '<p>' . esc_html__( 'There was a problem writing data to style.css.', 'child-theme-wizard' ) . '</p>';
$status['alert'] = -1;
return $status;
}
$status['message'] .= '<p>' . esc_html__( 'Writing data to style.css…', 'child-theme-wizard' ) . '</p>';
$functions = "<?php\n/*\n\n This file is part of a child theme called " . $safe['title'] . ".";
$functions .= "\n Functions in this file will be loaded before the parent theme's functions.";
$functions .= "\n For more information, please read";
$functions .= "\n https://developer.wordpress.org/themes/advanced-topics/child-themes/";
$functions .= "\n\n*/\n\n";
$functions .= "// Loads the parent stylesheet — leave this in place unless you know what you're doing.\n";
$functions .= "function your_theme_enqueue_styles() {\n\n";
$functions .= " \$parent_style = 'parent-style';\n\n";
$functions .= " wp_enqueue_style( \$parent_style,\n";
$functions .= " get_template_directory_uri() . '/style.css'\n";
$functions .= " );\n\n";
$functions .= " wp_enqueue_style( 'child-style',\n";
$functions .= " get_stylesheet_directory_uri() . '/style.css',\n";
$functions .= " array( \$parent_style ),\n";
$functions .= " wp_get_theme()->get( 'Version' )\n";
$functions .= " );\n";
$functions .= "}\n";
$functions .= "add_action( 'wp_enqueue_scripts', 'your_theme_enqueue_styles' );\n\n";
$functions .= "/* Add your own functions below this line.\n";
$functions .= " ======================================== */\n\n";
if ( ! $wp_filesystem->put_contents( $directory . '/functions.php', $functions, FS_CHMOD_FILE ) ) {
$status['message'] .= '<p>' . esc_html__( 'There was a problem writing data to functions.php.', 'child-theme-wizard' ) . '</p>';
$status['alert'] = -1;
return $status;
}
$status['message'] .= '<p>' . esc_html__( 'Writing data to functions.php…', 'child-theme-wizard' ) . '</p>';
$status['message'] .= ctw_make_thumbnail( $directory );
return $status;
}
function ctw_giveme_parents(): array {
$parent_themes = array();
foreach ( wp_get_themes() as $theme ) {
if ( $theme->parent() === false ) {
$parent_themes[] = $theme;
}
}
return $parent_themes;
}
function ctw_make_thumbnail( string $childpath ): string {
global $wp_filesystem;
if ( empty( $wp_filesystem ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
WP_Filesystem();
}
$source = plugin_dir_path( __FILE__ ) . 'images/screenshot.png';
$destination = $childpath . '/screenshot.png';
if ( ! $wp_filesystem->copy( $source, $destination ) ) {
return '<p>' . esc_html__( 'Could not copy thumbnail image.', 'child-theme-wizard' ) . '</p>';
}
return '<p>' . esc_html__( 'Copied thumbnail file — looking good!', 'child-theme-wizard' ) . '</p>';
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

@@ -0,0 +1,70 @@
=== Child Theme Wizard ===
Contributors: versluis
Donate link: https://patreon.com/versluis
Tags: child theme, generator, creator, one click, starter
Requires at least: 5.0
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 1.5
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Creates a child theme from any installed parent theme with just one click.
== Description ==
The Child Theme Wizard lets you create a new child theme without the need for additional tools, right from within the WordPress admin interface. Once activated you can find it under Tools - Child Theme Wizard.
Specify a parent theme, customise options such as title and description and click Create Child Theme. Upon success you will find your new theme under Appearance - Themes.
You have the option to include GPL License Terms if you wish. The Wizard will automatically create a thumbnail too.
To find out more about child themes and why they are useful, please read the [WordPress Developer Docs on Child Themes](https://developer.wordpress.org/themes/advanced-topics/child-themes/).
== Installation ==
1. Either: Upload the entire folder `child-theme-wizard` to the `/wp-content/plugins/` directory.
1. Or: download the ZIP file, then head over to Plugins - Add New - Upload Plugin, then browse to your file.
1. Or: from Plugins - Add New, search for "child theme wizard" to find this plugin and hit Install.
1. Then: Activate the plugin through the Plugins menu in WordPress.
1. You can find it under Tools - Child Theme Wizard.
== Screenshots ==
1. Create a Child Theme with just one click.
2. The wizard completed successfully.
3. Your new child theme appears under Appearance - Themes with a thumbnail.
== Changelog ==
= 1.5 =
* Security: added CSRF nonce protection to the creation form
* Security: parent theme selection now validated server-side against installed themes
* Security: all HTML output is now properly escaped
* Fixed: incorrect admin URL argument that broke the "Try again" link
* Fixed: missing closing </form> tag
* Fixed: thumbnail copy now uses the filesystem path instead of an HTTP URL, fixing failures on hosts with allow_url_fopen disabled
* Fixed: uninstall.php guard order corrected per WordPress standards
* Replaced direct PHP file functions (fopen, fwrite, fclose, mkdir, copy) with WP_Filesystem API
* Added PHP 8.2 return type declarations
* Removed unused ctw_testing() function
* Form layout updated to use WordPress standard form-table markup
* Tested with WordPress 7.0
= 1.4 =
* Defined the previously undefined variable $parent_style (thanks, Marcin!)
* Updated links to WordPress Dev Docs
= 1.3 =
* Tested compatibility with WordPress 5.1
* Updated link to Codex
* Added version query as suggested in Codex as of 2019
= 1.2 =
* Corrected a spelling mistake (thanks, Cory!)
= 1.1 =
* The parent theme stylesheet is now enqueued via functions.php
= 1.0 =
* Initial release
@@ -0,0 +1,7 @@
<?php
// Direct file access guard must come first.
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
// This plugin stores no options in the database, so there is nothing to clean up.