PluginProbe
Generate Child Theme / 2.3
Generate Child Theme v2.3
trunk 1.0.0 1.0.1 1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.2 1.5.3 1.6 1.7 1.8 1.9 2.0 2.0.1 2.1 2.1.1 2.2 2.3
generate-child-theme / generate-child-theme.php

generate-child-theme.php in Generate Child Theme 2.3, at generate-child-theme.php

368 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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