PluginProbe
Essential Widgets / 3.1
Essential Widgets v3.1
3.2.1 3.3 3.2 trunk 1.0.0 1.0.1 1.1 1.2 1.2.1 1.2.2 1.3 1.4 1.4.1 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.8 1.9 2.0 2.1 2.2 All 31 releases
← All changes | includes/CatchThemesThemePlugin.php +138 -143 1.7 → 3.1 View file →
@@ -1,8 +1,12 @@
1 1 <?php
2 2
3 -Class CatchThemesThemePlugin {
4 - public function __construct(){
3 +if ( ! defined( 'ABSPATH' ) ) {
4 + exit; // Exit if accessed directly.
5 +}
6 +
7 +class CatchThemesThemePlugin {
8 + public function __construct() {
5 9 remove_action( 'wp_ajax_query-themes', array( $this, 'wp_ajax_query_themes' ), 1 );
6 10 add_action( 'wp_ajax_query-themes', array( $this, 'wp_ajax_custom_query_themes' ), 1 );
7 11
8 12 add_action( 'admin_enqueue_scripts', array( $this, 'our_themes_script' ) );
@@ -15,40 +19,64 @@
15 19 remove_action( 'wp_ajax_customize_load_themes', array( $wp_customize, 'handle_load_themes_request' ) );
16 20 add_action( 'wp_ajax_customize_load_themes', array( $this, 'handle_load_themes_request' ) );
17 21
18 22 add_filter( 'install_plugins_tabs', array( $this, 'add_our_plugins_tab' ), 1 );
19 - add_filter( "install_plugins_table_api_args_catchplugins", array( $this, 'catchplugins' ), 1 );
23 + add_filter( 'install_plugins_table_api_args_catchplugins', array( $this, 'catchplugins' ), 1 );
20 24 add_action( 'install_plugins_catchplugins', array( $this, 'plugins_table' ) );
21 25 }
22 26
23 - /* Adds Catch Themes tab in Add Theme page to show all themes by Catch Themes in wordpress.org */
27 + /* Adds Catch Themes tab in Add Theme page to show all themes by Catch Themes in wordpress.org
28 + * taken from wp-admin/includes/ajax-action.php wp_ajax_query_themes().
29 + * Ajax handler for getting themes from themes_api().
30 + *
31 + * @since 3.9.0
32 + *
33 + * @global array $themes_allowedtags
34 + * @global array $theme_field_defaults
35 + */
24 36 public function wp_ajax_custom_query_themes() {
25 37 global $themes_allowedtags, $theme_field_defaults;
26 38
39 + // Capability check
27 40 if ( ! current_user_can( 'install_themes' ) ) {
28 41 wp_send_json_error();
29 42 }
30 43
31 - $args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
32 - 'per_page' => 20,
33 - 'fields' => $theme_field_defaults
34 - ) );
44 + // Nonce verification
45 + check_ajax_referer( 'ew_query_themes_nonce', 'nonce' );
35 46
47 + // Copy superglobal ONCE
48 + $post_data = wp_unslash( $_POST );
49 +
50 + // Now sanitize
51 + $post_data = map_deep( $post_data, 'sanitize_text_field' );
52 +
53 + // From this point on, DO NOT use $_POST again
54 + if ( empty( $post_data['request'] ) || ! is_array( $post_data['request'] ) ) {
55 + wp_send_json_error();
56 + }
57 +
58 + $args = wp_parse_args(
59 + $post_data['request'],
60 + array(
61 + 'per_page' => 20,
62 + 'fields' => array_merge(
63 + (array) $theme_field_defaults,
64 + array(
65 + 'reviews_url' => true,
66 + )
67 + ),
68 + )
69 + );
70 +
36 71 if ( isset( $args['browse'] ) && 'catchthemes' === $args['browse'] && ! isset( $args['user'] ) ) {
37 72 $args['author'] = 'catchthemes';
73 + unset( $args['browse'] );
38 74 }
39 75
40 - if ( isset( $args['browse'] ) && 'favorites' === $args['browse'] && ! isset( $args['user'] ) ) {
41 - $user = get_user_option( 'wporg_favorites' );
42 - if ( $user ) {
43 - $args['user'] = $user;
44 - }
45 - }
46 -
47 76 $old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
48 77
49 - /** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
50 - $args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
78 + $args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core WordPress hook, not plugin-defined.
51 79
52 80 $api = themes_api( 'query_themes', $args );
53 81
54 82 if ( is_wp_error( $api ) ) {
@@ -54,70 +82,45 @@
54 82 if ( is_wp_error( $api ) ) {
55 83 wp_send_json_error();
56 84 }
57 85
58 - $update_php = network_admin_url( 'update.php?action=install-theme' );
59 86 foreach ( $api->themes as &$theme ) {
60 - $theme->install_url = add_query_arg( array(
61 - 'theme' => $theme->slug,
62 - '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
63 - ), $update_php );
64 -
65 - if ( current_user_can( 'switch_themes' ) ) {
66 - if ( is_multisite() ) {
67 - $theme->activate_url = add_query_arg( array(
68 - 'action' => 'enable',
69 - '_wpnonce' => wp_create_nonce( 'enable-theme_' . $theme->slug ),
70 - 'theme' => $theme->slug,
71 - ), network_admin_url( 'themes.php' ) );
72 - } else {
73 - $theme->activate_url = add_query_arg( array(
74 - 'action' => 'activate',
75 - '_wpnonce' => wp_create_nonce( 'switch-theme_' . $theme->slug ),
76 - 'stylesheet' => $theme->slug,
77 - ), admin_url( 'themes.php' ) );
78 - }
79 - }
80 -
81 - if ( ! is_multisite() && current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
82 - $theme->customize_url = add_query_arg( array(
83 - 'return' => urlencode( network_admin_url( 'theme-install.php', 'relative' ) ),
84 - ), wp_customize_url( $theme->slug ) );
85 - }
86 -
87 87 $theme->name = wp_kses( $theme->name, $themes_allowedtags );
88 - $theme->author = wp_kses( $theme->author, $themes_allowedtags );
88 + $theme->author = wp_kses( $theme->author['display_name'], $themes_allowedtags );
89 89 $theme->version = wp_kses( $theme->version, $themes_allowedtags );
90 90 $theme->description = wp_kses( $theme->description, $themes_allowedtags );
91 - $theme->stars = wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings, 'echo' => false ) );
92 - $theme->num_ratings = number_format_i18n( $theme->num_ratings );
93 - $theme->preview_url = set_url_scheme( $theme->preview_url );
94 91 }
95 92
96 93 wp_send_json_success( $api );
97 94 }
98 -
95 +
99 96 public function our_themes_script( $hook_suffix ) {
100 97
101 - if( 'theme-install.php' == $hook_suffix ) {
102 - wp_enqueue_script( 'our-themes-script', plugin_dir_url( __FILE__ ) . '../admin/js/our-themes.js', array( 'jquery' ), '2018-05-16' );
98 + if ( 'theme-install.php' === $hook_suffix ) {
99 + wp_enqueue_script( 'our-themes-script', plugin_dir_url( __FILE__ ) . '../js/our-themes.js', array( 'jquery' ), '2018-05-16', true );
103 100 }
104 101 }
105 -
102 +
106 103 /* Add Catch Themes Section in Theme in Customizer */
107 - public function customize_register($wp_customize) {
108 - $wp_customize->add_section( new WP_Customize_Themes_Section( $wp_customize, 'catchthemes', array(
109 - 'title' => __( 'Themes by CatchThemes', 'catch-themes-demo-import' ),
110 - 'action' => 'catchthemes',
111 - 'capability' => 'install_themes',
112 - 'panel' => 'themes',
113 - 'priority' => 6,
114 - ) ) );
104 + public function customize_register( $wp_customize ) {
105 + $wp_customize->add_section(
106 + new WP_Customize_Themes_Section(
107 + $wp_customize,
108 + 'catchthemes',
109 + array(
110 + 'title' => __( 'Themes by CatchThemes', 'essential-widgets' ),
111 + 'action' => 'catchthemes',
112 + 'capability' => 'install_themes',
113 + 'panel' => 'themes',
114 + 'priority' => 6,
115 + )
116 + )
117 + );
115 118 }
116 -
117 119
118 120
119 -
121 +
122 +
120 123 /**
121 124 * Load themes into the theme browsing/installation UI.
122 125 * taken from wp-includes/cllass-wp-customize-manager.php
123 126 * @since 4.9.0
@@ -131,10 +134,10 @@
131 134 if ( empty( $_POST['theme_action'] ) ) {
132 135 wp_send_json_error( 'missing_theme_action' );
133 136 }
134 137 $theme_action = sanitize_key( $_POST['theme_action'] );
135 - $themes = array();
136 - $args = array();
138 + $themes = array();
139 + $args = array();
137 140
138 141 // Define query filters based on user input.
139 142 if ( ! array_key_exists( 'search', $_POST ) ) {
140 143 $args['search'] = '';
@@ -160,12 +163,11 @@
160 163
161 164 // Load all installed themes from wp_prepare_themes_for_js().
162 165 $themes = array( 'themes' => wp_prepare_themes_for_js() );
163 166 foreach ( $themes['themes'] as &$theme ) {
164 - $theme['type'] = 'installed';
167 + $theme['type'] = 'installed';
165 168 $theme['active'] = ( isset( $_POST['customized_theme'] ) && $_POST['customized_theme'] === $theme['id'] );
166 169 }
167 -
168 170 } elseif ( 'catchthemes' === $theme_action ) {
169 171
170 172 // Load WordPress.org themes from the .org API and normalize data to match installed theme objects.
171 173 if ( ! current_user_can( 'install_themes' ) ) {
@@ -173,21 +175,11 @@
173 175 }
174 176
175 177 // Arguments for all queries.
176 178 $wporg_args = array(
177 - 'per_page' => -1,
178 - 'fields' => array(
179 - 'screenshot_url' => true,
180 - 'description' => true,
181 - 'rating' => true,
182 - 'downloaded' => true,
183 - 'downloadlink' => true,
184 - 'last_updated' => true,
185 - 'homepage' => true,
186 - 'num_ratings' => true,
187 - 'tags' => true,
188 - 'parent' => true,
189 - // 'extended_author' => true, @todo: WordPress.org throws a 500 server error when this is here.
179 + 'per_page' => 100,
180 + 'fields' => array(
181 + 'reviews_url' => true, // Explicitly request the reviews URL to be linked from the customizer.
190 182 ),
191 183 );
192 184
193 185 $args = array_merge( $wporg_args, $args );
@@ -204,20 +196,20 @@
204 196 wp_send_json_error();
205 197 }
206 198
207 199 // This list matches the allowed tags in wp-admin/includes/theme-install.php.
208 - $themes_allowedtags = array_fill_keys(
200 + $themes_allowedtags = array_fill_keys(
209 201 array( 'a', 'abbr', 'acronym', 'code', 'pre', 'em', 'strong', 'div', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img' ),
210 202 array()
211 203 );
212 - $themes_allowedtags['a'] = array_fill_keys( array( 'href', 'title', 'target' ), true );
204 + $themes_allowedtags['a'] = array_fill_keys( array( 'href', 'title', 'target' ), true );
213 205 $themes_allowedtags['acronym']['title'] = true;
214 - $themes_allowedtags['abbr']['title'] = true;
215 - $themes_allowedtags['img'] = array_fill_keys( array( 'src', 'class', 'alt' ), true );
206 + $themes_allowedtags['abbr']['title'] = true;
207 + $themes_allowedtags['img'] = array_fill_keys( array( 'src', 'class', 'alt' ), true );
216 208
217 209 // Prepare a list of installed themes to check against before the loop.
218 210 $installed_themes = array();
219 - $wp_themes = wp_get_themes();
211 + $wp_themes = wp_get_themes();
220 212 foreach ( $wp_themes as $theme ) {
221 213 $installed_themes[] = $theme->get_stylesheet();
222 214 }
223 215 $update_php = network_admin_url( 'update.php?action=install-theme' );
@@ -223,24 +215,27 @@
223 215 $update_php = network_admin_url( 'update.php?action=install-theme' );
224 216
225 217 // Set up properties for themes available on WordPress.org.
226 218 foreach ( $themes->themes as &$theme ) {
227 - $theme->install_url = add_query_arg( array(
228 - 'theme' => $theme->slug,
229 - '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug ),
230 - ), $update_php );
219 + $theme->install_url = add_query_arg(
220 + array(
221 + 'theme' => $theme->slug,
222 + '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug ),
223 + ),
224 + $update_php
225 + );
231 226
232 227 $theme->name = wp_kses( $theme->name, $themes_allowedtags );
233 - $theme->author = wp_kses( $theme->author, $themes_allowedtags );
234 228 $theme->version = wp_kses( $theme->version, $themes_allowedtags );
235 229 $theme->description = wp_kses( $theme->description, $themes_allowedtags );
236 - $theme->tags = implode( ', ', $theme->tags );
237 - $theme->stars = wp_star_rating( array(
238 - 'rating' => $theme->rating,
239 - 'type' => 'percent',
240 - 'number' => $theme->num_ratings,
241 - 'echo' => false,
242 - ) );
230 + $theme->stars = wp_star_rating(
231 + array(
232 + 'rating' => $theme->rating,
233 + 'type' => 'percent',
234 + 'number' => $theme->num_ratings,
235 + 'echo' => false,
236 + )
237 + );
243 238 $theme->num_ratings = number_format_i18n( $theme->num_ratings );
244 239 $theme->preview_url = set_url_scheme( $theme->preview_url );
245 240
246 241 // Handle themes that are already installed as installed themes.
@@ -253,12 +248,14 @@
253 248 // Set active based on customized theme.
254 249 $theme->active = ( isset( $_POST['customized_theme'] ) && $_POST['customized_theme'] === $theme->slug );
255 250
256 251 // Map available theme properties to installed theme properties.
257 - $theme->id = $theme->slug;
258 - $theme->screenshot = array( $theme->screenshot_url );
259 - $theme->authorAndUri = $theme->author;
260 - // The .org API can return the full parent theme details if passed the 'parent' arg, or if passed the 'template' option it'll return that in the event it's a child theme.
252 + $theme->id = $theme->slug;
253 + $theme->screenshot = array( $theme->screenshot_url );
254 + $theme->authorAndUri = wp_kses( $theme->author['display_name'], $themes_allowedtags );
255 + $theme->compatibleWP = is_wp_version_compatible( $theme->requires ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName
256 + $theme->compatiblePHP = is_php_version_compatible( $theme->requires_php ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName
257 +
261 258 if ( isset( $theme->parent ) ) {
262 259 $theme->parent = $theme->parent['slug'];
263 260 } else {
264 261 $theme->parent = false;
@@ -277,19 +274,9 @@
277 274 // Arguments for all queries.
278 275 $wporg_args = array(
279 276 'per_page' => 100,
280 277 'fields' => array(
281 - 'screenshot_url' => true,
282 - 'description' => true,
283 - 'rating' => true,
284 - 'downloaded' => true,
285 - 'downloadlink' => true,
286 - 'last_updated' => true,
287 - 'homepage' => true,
288 - 'num_ratings' => true,
289 - 'tags' => true,
290 - 'parent' => true,
291 - // 'extended_author' => true, @todo: WordPress.org throws a 500 server error when this is here.
278 + 'reviews_url' => true, // Explicitly request the reviews URL to be linked from the customizer.
292 279 ),
293 280 );
294 281
295 282 $args = array_merge( $wporg_args, $args );
@@ -304,9 +291,9 @@
304 291 wp_send_json_error();
305 292 }
306 293
307 294 // This list matches the allowed tags in wp-admin/includes/theme-install.php.
308 - $themes_allowedtags = array_fill_keys(
295 + $themes_allowedtags = array_fill_keys(
309 296 array( 'a', 'abbr', 'acronym', 'code', 'pre', 'em', 'strong', 'div', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img' ),
310 297 array()
311 298 );
312 299 $themes_allowedtags['a'] = array_fill_keys( array( 'href', 'title', 'target' ), true );
@@ -315,9 +302,9 @@
315 302 $themes_allowedtags['img'] = array_fill_keys( array( 'src', 'class', 'alt' ), true );
316 303
317 304 // Prepare a list of installed themes to check against before the loop.
318 305 $installed_themes = array();
319 - $wp_themes = wp_get_themes();
306 + $wp_themes = wp_get_themes();
320 307 foreach ( $wp_themes as $theme ) {
321 308 $installed_themes[] = $theme->get_stylesheet();
322 309 }
323 310 $update_php = network_admin_url( 'update.php?action=install-theme' );
@@ -323,24 +310,27 @@
323 310 $update_php = network_admin_url( 'update.php?action=install-theme' );
324 311
325 312 // Set up properties for themes available on WordPress.org.
326 313 foreach ( $themes->themes as &$theme ) {
327 - $theme->install_url = add_query_arg( array(
328 - 'theme' => $theme->slug,
329 - '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug ),
330 - ), $update_php );
314 + $theme->install_url = add_query_arg(
315 + array(
316 + 'theme' => $theme->slug,
317 + '_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug ),
318 + ),
319 + $update_php
320 + );
331 321
332 322 $theme->name = wp_kses( $theme->name, $themes_allowedtags );
333 - $theme->author = wp_kses( $theme->author, $themes_allowedtags );
334 323 $theme->version = wp_kses( $theme->version, $themes_allowedtags );
335 324 $theme->description = wp_kses( $theme->description, $themes_allowedtags );
336 - $theme->tags = implode( ', ', $theme->tags );
337 - $theme->stars = wp_star_rating( array(
338 - 'rating' => $theme->rating,
339 - 'type' => 'percent',
340 - 'number' => $theme->num_ratings,
341 - 'echo' => false,
342 - ) );
325 + $theme->stars = wp_star_rating(
326 + array(
327 + 'rating' => $theme->rating,
328 + 'type' => 'percent',
329 + 'number' => $theme->num_ratings,
330 + 'echo' => false,
331 + )
332 + );
343 333 $theme->num_ratings = number_format_i18n( $theme->num_ratings );
344 334 $theme->preview_url = set_url_scheme( $theme->preview_url );
345 335
346 336 // Handle themes that are already installed as installed themes.
@@ -353,12 +343,14 @@
353 343 // Set active based on customized theme.
354 344 $theme->active = ( isset( $_POST['customized_theme'] ) && $_POST['customized_theme'] === $theme->slug );
355 345
356 346 // Map available theme properties to installed theme properties.
357 - $theme->id = $theme->slug;
358 - $theme->screenshot = array( $theme->screenshot_url );
359 - $theme->authorAndUri = $theme->author;
360 - // The .org API can return the full parent theme details if passed the 'parent' arg, or if passed the 'template' option it'll return that in the event it's a child theme.
347 + $theme->id = $theme->slug;
348 + $theme->screenshot = array( $theme->screenshot_url );
349 + $theme->authorAndUri = wp_kses( $theme->author['display_name'], $themes_allowedtags );
350 + $theme->compatibleWP = is_wp_version_compatible( $theme->requires ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName
351 + $theme->compatiblePHP = is_php_version_compatible( $theme->requires_php ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName
352 +
361 353 if ( isset( $theme->parent ) ) {
362 354 $theme->parent = $theme->parent['slug'];
363 355 } else {
364 356 $theme->parent = false;
@@ -385,22 +377,21 @@
385 377 * @param array $themes Nested array of theme data.
386 378 * @param array $args List of arguments, such as page, search term, and tags to query for.
387 379 * @param WP_Customize_Manager $manager Instance of Customize manager.
388 380 */
389 - $themes = apply_filters( 'customize_load_themes', $themes, $args, $wp_customize );
381 + $themes = apply_filters( 'customize_load_themes', $themes, $args, $wp_customize ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core WordPress hook, not plugin-defined.
390 382
391 383 wp_send_json_success( $themes );
392 384 }
393 385
394 - /* Plugins */
395 - /* Adds Catch Plugins tab in Add Plugin page to show all plugins by Catch Plugins in wordpress.org */
396 - public function add_our_plugins_tab($tabs) {
397 - // Add our filter here
398 - $tabs['catchplugins'] = _x( 'Catch Plugins', 'Plugin Installer' );
386 + public function add_our_plugins_tab( $tabs ) {
387 + // Translators: Tab label in the Plugin Installer for listing Catch Plugins.
388 + $tabs['catchplugins'] = _x( 'Catch Plugins', 'Plugin Installer', 'essential-widgets' );
399 389
400 - return $tabs;
390 + return $tabs;
401 391 }
402 392
393 +
403 394 public function catchplugins() {
404 395 /* From CORE Start */
405 396 global $paged, $tab;
406 397 wp_reset_vars( array( 'tab' ) );
@@ -405,9 +396,9 @@
405 396 global $paged, $tab;
406 397 wp_reset_vars( array( 'tab' ) );
407 398
408 399 $defined_class = new WP_Plugin_Install_List_Table();
409 - $paged = $defined_class->get_pagenum();
400 + $paged = $defined_class->get_pagenum();
410 401
411 402 $per_page = 30;
412 403 //$installed_plugins = catch_get_installed_plugins();
413 404
@@ -416,12 +407,12 @@
416 407 'per_page' => $per_page,
417 408 'fields' => array(
418 409 'last_updated' => true,
419 410 'icons' => true,
420 - 'active_installs' => true
411 + 'active_installs' => true,
421 412 ),
422 413 // Send the locale and installed plugin slugs to the API so it can provide context-sensitive results.
423 - 'locale' => get_user_locale(),
414 + 'locale' => get_user_locale(),
424 415 //'installed_plugins' => array_keys( $installed_plugins ),
425 416 );
426 417 /* From CORE End */
427 418
@@ -433,10 +424,14 @@
433 424
434 425 public function plugins_table() {
435 426 global $wp_list_table;
436 427 printf(
437 - '<p class="catch-plugins-list">' . __( 'You can use any of our free plugins or premium plugins from <a href="%s" target="_blank">Catch Plugins</a>' ) . '.</p>',
438 - 'https://catchplugins.com/'
428 + '<p class="catch-plugins-list">%s</p>',
429 + sprintf(
430 + // Translators: %s is the URL to the Catch Plugins website.
431 + wp_kses_post( __( 'You can use any of our free plugins or premium plugins from <a href="%s" target="_blank">Catch Plugins</a>.', 'essential-widgets' ) ),
432 + esc_url( 'https://catchplugins.com/' )
433 + )
439 434 );
440 435 ?>
441 436 <form id="plugin-filter" method="post">
442 437 <?php $wp_list_table->display(); ?>
@@ -444,5 +439,5 @@
444 439 <?php
445 440 }
446 441 }
447 442
448 -$catchthemes_theme_plugin = new CatchThemesThemePlugin();
443 +$catchthemes_theme_plugin = new CatchThemesThemePlugin(); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- File-scope bootstrap variable used immediately.