| 1 |
<?php |
| 2 |
/** |
| 3 |
* The plugin bootstrap file |
| 4 |
* |
| 5 |
* This file is read by WordPress to generate the plugin information in the plugin |
| 6 |
* admin area. This file also includes all of the dependencies used by the plugin, |
| 7 |
* registers the activation and deactivation functions, and defines a function |
| 8 |
* that starts the plugin. |
| 9 |
* |
| 10 |
* @link catchplugins.com |
| 11 |
* @since 1.0.0 |
| 12 |
* @package Generate_Child_Theme |
| 13 |
* |
| 14 |
* @wordpress-plugin |
| 15 |
* Plugin Name: Generate Child Theme |
| 16 |
* Plugin URI: http://catchplugins.com/plugins/generate-child-theme |
| 17 |
* Description: Create child themes of any WordPress themes effortlessly with Generate Child Theme. |
| 18 |
* Version: 2.3 |
| 19 |
* Author: Catch Plugins |
| 20 |
* Author URI: http://catchplugins.com |
| 21 |
* License: GPL-2.0+ |
| 22 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt |
| 23 |
* Text Domain: generate-child-theme |
| 24 |
* Domain Path: /languages |
| 25 |
*/ |
| 26 |
|
| 27 |
// If this file is called directly, abort. |
| 28 |
if (! defined('WPINC')) { |
| 29 |
die; |
| 30 |
} |
| 31 |
|
| 32 |
/** |
| 33 |
* Currently plugin version. |
| 34 |
* Start at version 1.0.0 and use SemVer - https://semver.org |
| 35 |
* Rename this for your plugin and update it as you release new versions. |
| 36 |
*/ |
| 37 |
if ( ! defined( 'GENERATECHILDTHEME_VERSION' ) ) { |
| 38 |
define( 'GENERATECHILDTHEME_VERSION', '2.3' ); |
| 39 |
} |
| 40 |
|
| 41 |
// The URL of the directory that contains the plugin |
| 42 |
if (! defined('GENERATECHILDTHEME_URL')) { |
| 43 |
define('GENERATECHILDTHEME_URL', plugin_dir_url(__FILE__)); |
| 44 |
} |
| 45 |
|
| 46 |
// The absolute path of the directory that contains the file |
| 47 |
if (! defined('GENERATECHILDTHEME_PATH')) { |
| 48 |
define('GENERATECHILDTHEME_PATH', plugin_dir_path(__FILE__)); |
| 49 |
} |
| 50 |
|
| 51 |
class Generate_Child_Theme // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Generate_Child_Theme matches the plugin slug; used as a single instance via generate_child_theme_run(). |
| 52 |
{ |
| 53 |
|
| 54 |
public function __construct() |
| 55 |
{ |
| 56 |
add_action('admin_menu', array($this, 'add_plugin_settings_menu')); |
| 57 |
add_action('admin_post_create', array($this, 'process_create_form')); |
| 58 |
add_filter('plugin_row_meta', array($this, 'add_plugin_meta_links'), 10, 2); |
| 59 |
|
| 60 |
// phpcs:disable WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- read-only display checks; no data is processed or stored. |
| 61 |
$gct_php_self = isset( $_SERVER['PHP_SELF'] ) ? sanitize_text_field( wp_unslash( $_SERVER['PHP_SELF'] ) ) : ''; |
| 62 |
$gct_ctcm_status = isset( $_REQUEST['ctcm_status'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ctcm_status'] ) ) : ''; |
| 63 |
// phpcs:enable WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash |
| 64 |
if ( 'themes.php' === basename( $gct_php_self ) && ! empty( $gct_ctcm_status ) ) { |
| 65 |
add_action('admin_notices', array($this, 'showErrorNotice')); |
| 66 |
} |
| 67 |
|
| 68 |
add_action('admin_enqueue_scripts', array($this, 'enqueue_styles')); |
| 69 |
add_action('admin_enqueue_scripts', array($this, 'enqueue_scripts')); |
| 70 |
} |
| 71 |
|
| 72 |
public function add_plugin_settings_menu() |
| 73 |
{ |
| 74 |
add_menu_page( |
| 75 |
esc_html__('Generate Child Theme', 'generate-child-theme'), //page title |
| 76 |
esc_html__('Generate Child Theme', 'generate-child-theme'), //menu title |
| 77 |
'install_themes', //capability needed |
| 78 |
'generate-child-theme', //menu slug (and page query url) |
| 79 |
array($this, 'generate_child_theme'), |
| 80 |
'dashicons-admin-appearance', |
| 81 |
'99.01564' |
| 82 |
); |
| 83 |
} |
| 84 |
|
| 85 |
public function generate_child_theme() |
| 86 |
{ |
| 87 |
$child_theme = false; |
| 88 |
if (! current_user_can('install_themes')) { |
| 89 |
wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'generate-child-theme')); |
| 90 |
} |
| 91 |
|
| 92 |
require_once plugin_dir_path(__FILE__) . 'partials/generate-child-theme-admin-display.php'; |
| 93 |
} |
| 94 |
|
| 95 |
public function process_create_form() |
| 96 |
{ |
| 97 |
// Verify nonce |
| 98 |
if (! empty($_POST) && isset($_POST['generate_child_theme_nonce_field']) && wp_verify_nonce(sanitize_key(wp_unslash($_POST['generate_child_theme_nonce_field'])), 'generate_child_theme_nonce')) { |
| 99 |
|
| 100 |
// Process form data |
| 101 |
$info = array( |
| 102 |
'parent_theme_template' => isset($_POST['parent_template']) ? sanitize_text_field(wp_unslash($_POST['parent_template'])) : '', |
| 103 |
'theme_name' => isset($_POST['child_theme_name']) ? sanitize_text_field(wp_unslash($_POST['child_theme_name'])) : '', |
| 104 |
'theme_description' => empty($_POST['child_theme_description']) ? 'Your description goes here' : sanitize_text_field(wp_unslash($_POST['child_theme_description'])), |
| 105 |
'theme_author' => isset($_POST['child_theme_author']) ? sanitize_text_field(wp_unslash($_POST['child_theme_author'])) : '', |
| 106 |
'theme_version' => empty($_POST['child_theme_version']) ? '1.0' : sanitize_text_field(wp_unslash($_POST['child_theme_version'])), |
| 107 |
); |
| 108 |
|
| 109 |
$result = $this->make_child_theme($info); |
| 110 |
|
| 111 |
if (is_wp_error($result)) { |
| 112 |
// should show create child form again |
| 113 |
$this->_redirect( |
| 114 |
admin_url('themes.php?page=generate-child-theme'), |
| 115 |
$result->get_error_message(), |
| 116 |
array( |
| 117 |
'theme_name' => $info['theme_name'], |
| 118 |
'description' => $info['theme_description'], |
| 119 |
'author_name' => $info['theme_author'], |
| 120 |
'theme_version' => $info['theme_version'], |
| 121 |
) |
| 122 |
); |
| 123 |
return; |
| 124 |
} else { |
| 125 |
switch_theme($result['parent_template'], $result['new_child_theme']); |
| 126 |
// Redirect to themes page on success |
| 127 |
$this->_redirect(admin_url('themes.php'), 'child_created'); |
| 128 |
} |
| 129 |
} else { |
| 130 |
// Nonce verification failed, display error message |
| 131 |
wp_die( esc_html__( 'Security check failed. Please try again.', 'generate-child-theme' ) ); |
| 132 |
} |
| 133 |
} |
| 134 |
|
| 135 |
function add_plugin_meta_links($meta_fields, $file) |
| 136 |
{ |
| 137 |
|
| 138 |
if ($file === plugin_basename(__FILE__)) { |
| 139 |
|
| 140 |
$meta_fields[] = "<a href='https://catchplugins.com/support-forum/forum/generate-child-theme/' target='_blank'>Support Forum</a>"; |
| 141 |
$meta_fields[] = "<a href='https://wordpress.org/support/plugin/generate-child-theme/reviews#new-post' target='_blank' title='Rate'> |
| 142 |
<i class='ct-rate-stars'>" |
| 143 |
. "<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-star'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>" |
| 144 |
. "<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-star'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>" |
| 145 |
. "<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-star'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>" |
| 146 |
. "<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-star'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>" |
| 147 |
. "<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-star'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>" |
| 148 |
. '</i></a>'; |
| 149 |
|
| 150 |
$stars_color = '#ffb900'; |
| 151 |
|
| 152 |
echo '<style>' |
| 153 |
. '.ct-rate-stars{display:inline-block;color:' . esc_html($stars_color) . ';position:relative;top:3px;}' |
| 154 |
. '.ct-rate-stars svg{fill:' . esc_html($stars_color) . ';}' |
| 155 |
. '.ct-rate-stars svg:hover{fill:' . esc_html($stars_color) . '}' |
| 156 |
. '.ct-rate-stars svg:hover ~ svg{fill:none;}' |
| 157 |
. '</style>'; |
| 158 |
} |
| 159 |
|
| 160 |
return $meta_fields; |
| 161 |
} |
| 162 |
|
| 163 |
public function make_child_theme($info) |
| 164 |
{ |
| 165 |
$data = explode(':', $info['parent_theme_template']); |
| 166 |
$parent_theme_name = $data[1]; |
| 167 |
$parent_theme_template = $data[0]; |
| 168 |
$theme_root = get_theme_root(); |
| 169 |
$parent_theme_dir = $theme_root . '/' . $parent_theme_template; |
| 170 |
$theme_name = $info['theme_name']; |
| 171 |
$description = $info['theme_description']; |
| 172 |
$author = $info['theme_author']; |
| 173 |
$version = $info['theme_version']; |
| 174 |
|
| 175 |
// Turn a theme name into a directory name |
| 176 |
$new_theme_name = sanitize_title($theme_name); |
| 177 |
|
| 178 |
$theme_slug = str_replace('-', '_', $new_theme_name); |
| 179 |
|
| 180 |
$new_child_theme_path = $theme_root . '/' . $new_theme_name; |
| 181 |
|
| 182 |
require_once(ABSPATH . 'wp-admin/includes/file.php'); |
| 183 |
|
| 184 |
global $wp_filesystem; |
| 185 |
|
| 186 |
if (! $wp_filesystem) { |
| 187 |
WP_Filesystem(); // Initialize the filesystem object |
| 188 |
} |
| 189 |
|
| 190 |
|
| 191 |
if (file_exists($new_child_theme_path)) { |
| 192 |
wp_die(esc_html__('The directory already exists', 'generate-child-theme')); |
| 193 |
return; |
| 194 |
} |
| 195 |
if (! $wp_filesystem->is_dir($new_child_theme_path)) { |
| 196 |
$wp_filesystem->mkdir($new_child_theme_path); |
| 197 |
} |
| 198 |
|
| 199 |
// Make style.css |
| 200 |
ob_start(); |
| 201 |
require plugin_dir_path(__FILE__) . 'templates/child-theme-css.php'; |
| 202 |
$css = ob_get_clean(); |
| 203 |
$wp_filesystem->put_contents($new_child_theme_path . '/style.css', $css, FS_CHMOD_FILE); |
| 204 |
|
| 205 |
$function_prefix = $theme_slug; |
| 206 |
|
| 207 |
if (preg_match('/^\d/', $function_prefix)) { |
| 208 |
$function_prefix = 'cp_' . $function_prefix; |
| 209 |
} |
| 210 |
|
| 211 |
// Make functions.php |
| 212 |
$function_content = "<?php |
| 213 |
/* |
| 214 |
* This is the child theme for {$parent_theme_name} theme, generated with Generate Child Theme plugin by catchthemes. |
| 215 |
* |
| 216 |
* (Please see https://developer.wordpress.org/themes/advanced-topics/child-themes/#how-to-create-a-child-theme) |
| 217 |
*/ |
| 218 |
add_action( 'wp_enqueue_scripts', '{$function_prefix}_enqueue_styles' ); |
| 219 |
function {$function_prefix}_enqueue_styles() { |
| 220 |
wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' ); |
| 221 |
wp_enqueue_style( 'child-style', |
| 222 |
get_stylesheet_directory_uri() . '/style.css', |
| 223 |
array('parent-style') |
| 224 |
); |
| 225 |
} |
| 226 |
/* |
| 227 |
* Your code goes below |
| 228 |
*/"; |
| 229 |
|
| 230 |
$wp_filesystem->put_contents($new_child_theme_path . '/functions.php', $function_content, FS_CHMOD_FILE); |
| 231 |
|
| 232 |
// RTL support |
| 233 |
$rtl_theme = (file_exists($parent_theme_dir . '/rtl.css')) |
| 234 |
? $parent_theme_template |
| 235 |
: 'twentyseventeen'; //use the latest default theme rtl file |
| 236 |
ob_start(); |
| 237 |
require plugin_dir_path(__FILE__) . 'templates/rtl-css.php'; |
| 238 |
$css = ob_get_clean(); |
| 239 |
$wp_filesystem->put_contents($new_child_theme_path . '/rtl.css', $css, FS_CHMOD_FILE); |
| 240 |
|
| 241 |
// Copy screenshot |
| 242 |
if ($screenshot_template = $this->get_screenshot($parent_theme_dir)) { |
| 243 |
copy( |
| 244 |
$parent_theme_dir . '/' . $screenshot_template, |
| 245 |
$new_child_theme_path . '/' . $screenshot_template |
| 246 |
); |
| 247 |
} // removed grandfather screenshot check (use mshot instead, rly) |
| 248 |
|
| 249 |
// Make child theme an allowed theme (network enable theme) |
| 250 |
$allowed_themes = get_site_option('allowedthemes'); |
| 251 |
$allowed_themes[$new_theme_name] = true; |
| 252 |
update_site_option('allowedthemes', $allowed_themes); |
| 253 |
|
| 254 |
return array( |
| 255 |
'parent_template' => $parent_theme_template, |
| 256 |
'parent_theme' => $parent_theme_name, |
| 257 |
'new_child_theme' => $new_theme_name, |
| 258 |
'new_child_theme_path' => $new_child_theme_path, |
| 259 |
'new_child_theme_title' => $theme_name, |
| 260 |
); |
| 261 |
} |
| 262 |
|
| 263 |
public function get_screenshot($directory) |
| 264 |
{ |
| 265 |
$screenshots = glob($directory . '/screenshot.{png,jpg,jpeg,gif}', GLOB_BRACE); |
| 266 |
return (empty($screenshots)) ? false : basename($screenshots[0]); |
| 267 |
} |
| 268 |
|
| 269 |
|
| 270 |
public function _redirect($url, $status, $args = array()) |
| 271 |
{ |
| 272 |
$args['ctcm_status'] = $status; |
| 273 |
$args = urlencode_deep($args); |
| 274 |
wp_safe_redirect(add_query_arg($args, $url)); |
| 275 |
exit; |
| 276 |
} |
| 277 |
|
| 278 |
public function showErrorNotice() |
| 279 |
{ |
| 280 |
$ctcm_status = isset( $_GET['ctcm_status'] ) ? sanitize_text_field( wp_unslash( $_GET['ctcm_status'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only display check; value was set by this plugin's own wp_safe_redirect(). |
| 281 |
switch ( $ctcm_status ) { |
| 282 |
case 'child_created': //SUCCESS: child theme created |
| 283 |
$type = 'updated'; //fade? |
| 284 |
// translators: %s is a stylesheet of a switched theme for edit. |
| 285 |
$switched_msg = __( 'Theme switched! <a href="%s">Click here to edit the child stylesheet</a>.', 'generate-child-theme' ); |
| 286 |
$msg = sprintf( |
| 287 |
wp_kses_post( $switched_msg ), |
| 288 |
add_query_arg( |
| 289 |
urlencode_deep( |
| 290 |
array( |
| 291 |
'file' => 'style.css', |
| 292 |
'theme' => get_stylesheet(), |
| 293 |
) |
| 294 |
), |
| 295 |
admin_url('theme-editor.php') |
| 296 |
) |
| 297 |
); |
| 298 |
break; |
| 299 |
case 'create_failed': //ERROR: create file failed (probably due to permissions) |
| 300 |
$type = 'error'; |
| 301 |
// translators: %s is error template failed to create. |
| 302 |
$failed_msg = __( 'Failed to create file: %s', 'generate-child-theme' ); |
| 303 |
$msg = sprintf( |
| 304 |
wp_kses_post( $failed_msg ), |
| 305 |
esc_html( isset( $_GET['template'] ) ? sanitize_text_field( wp_unslash( $_GET['template'] ) ) : '' ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only display check; value was set by this plugin's own wp_safe_redirect(). |
| 306 |
); |
| 307 |
break; |
| 308 |
default: //ERROR: it is a generic error message |
| 309 |
$type = 'error'; |
| 310 |
$msg = esc_html( $ctcm_status ); |
| 311 |
} |
| 312 |
|
| 313 |
printf( |
| 314 |
'<div class="%s"><p>%s</p></div>', |
| 315 |
esc_html($type), |
| 316 |
wp_kses_post($msg) |
| 317 |
); |
| 318 |
} |
| 319 |
|
| 320 |
|
| 321 |
public function enqueue_styles() |
| 322 |
{ |
| 323 |
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing check; no data is processed. |
| 324 |
if ( 'generate-child-theme' === $page ) { |
| 325 |
wp_enqueue_style('generate-child-theme', plugin_dir_url(__FILE__) . 'css/generate-child-theme.css', array(), GENERATECHILDTHEME_VERSION, 'all'); |
| 326 |
wp_enqueue_style('generate-child-theme-tabs', plugin_dir_url(__FILE__) . 'css/admin-dashboard.css', array(), GENERATECHILDTHEME_VERSION, 'all'); |
| 327 |
} |
| 328 |
} |
| 329 |
|
| 330 |
public function enqueue_scripts() |
| 331 |
{ |
| 332 |
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing check; no data is processed. |
| 333 |
if ( 'generate-child-theme' === $page ) { |
| 334 |
wp_enqueue_script('minHeight', plugin_dir_url(__FILE__) . 'js/jquery.matchHeight.min.js', array('jquery'), GENERATECHILDTHEME_VERSION, true); |
| 335 |
wp_enqueue_script('generate-child-theme-js', plugin_dir_url(__FILE__) . 'js/generate-child-theme-admin.js', array('minHeight', 'jquery'), GENERATECHILDTHEME_VERSION, true); |
| 336 |
} |
| 337 |
} |
| 338 |
|
| 339 |
public static function get_theme_list() |
| 340 |
{ |
| 341 |
$themes = wp_get_themes(); |
| 342 |
$list = array(); |
| 343 |
foreach ($themes as $theme) { |
| 344 |
if ($theme->parent() === false) { |
| 345 |
$list[$theme['Template'] . ':' . $theme['Name']] = $theme['Name']; |
| 346 |
} |
| 347 |
} |
| 348 |
return $list; |
| 349 |
} |
| 350 |
} |
| 351 |
|
| 352 |
function generate_child_theme_run() |
| 353 |
{ |
| 354 |
new Generate_Child_Theme(); |
| 355 |
} |
| 356 |
generate_child_theme_run(); |
| 357 |
|
| 358 |
/* CTP tabs removal options */ |
| 359 |
require plugin_dir_path(__FILE__) . 'partials/ctp-tabs-removal.php'; |
| 360 |
|
| 361 |
$ctp_options = ctp_get_options(); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- file-scope bootstrap variable used immediately below. |
| 362 |
if (1 === $ctp_options['theme_plugin_tabs']) { |
| 363 |
/* Adds Catch Themes tab in Add theme page and Themes by Catch Themes in Customizer's change theme option. */ |
| 364 |
if (! class_exists('CatchThemesThemePlugin') && ! function_exists('add_our_plugins_tab')) { |
| 365 |
require plugin_dir_path(__FILE__) . 'partials/CatchThemesThemePlugin.php'; |
| 366 |
} |
| 367 |
} |
| 368 |
|