PluginProbe
Responsive Menu – Create Mobile-Friendly Menu / 4.7.4
Responsive Menu – Create Mobile-Friendly Menu v4.7.4
4.7.4 4.7.3 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.10 4.1.11 4.1.12 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 All 91 releases
← All changes | v4.0.0/inc/classes/class-theme-manager.php +1285 -289 4.0.0 → 4.7.4 View file →
@@ -1,29 +1,29 @@
1 1 <?php
2 2 /**
3 3 * This file contain the Theme_Manager class and it's functionalities for menu.
4 - *
4 + *
5 5 * @version 4.0.0
6 6 * @author Expresstech System
7 - *
8 - * @package responsive-menu-pro
7 + *
8 + * @package responsive-menu
9 9 */
10 10
11 11 namespace RMP\Features\Inc;
12 12
13 13 use RMP\Features\Inc\Traits\Singleton;
14 -use responsive_menu_pro\frontend\RMP_Menu;
14 +use RMP\Features\Inc\Option_Manager;
15 15
16 16 // Disable the direct access to this class.
17 17 if ( ! defined( 'ABSPATH' ) ) {
18 - exit;
18 + exit;
19 19 }
20 20
21 21 /**
22 22 * Class Theme_Manager
23 23 * This class is handling the menu themes and its functionalities.
24 - *
25 - * @version 4.0.0
24 + *
25 + * @since 4.0.0
26 26 */
27 27 class Theme_Manager {
28 28
29 29 use Singleton;
@@ -29,13 +29,100 @@
29 29 use Singleton;
30 30
31 31 /**
32 32 * This is option key where saved themes are stored.
33 + *
33 34 * @var string $theme_option
34 35 */
35 36 protected static $theme_option = 'rmp_themes';
36 37
37 38 /**
39 + * This is default theme preview image url
40 + *
41 + * @var string $theme_preview_img
42 + */
43 + public $theme_preview_img = RMP_PLUGIN_URL_V4 . '/assets/images/default-theme-preview.png';
44 +
45 + /**
46 + * Capability required to upload a menu theme.
47 + *
48 + * A menu theme ships a PHP index file which the plugin loads with
49 + * require_once on every request, so uploading one is equivalent to
50 + * installing a plugin and must require the same capability. On multisite
51 + * `install_plugins` belongs to Super Admins only, which closes the
52 + * privilege boundary a site Administrator could otherwise cross.
53 + *
54 + * @since 4.7.3
55 + *
56 + * @var string
57 + */
58 + const THEME_UPLOAD_CAPABILITY = 'install_plugins';
59 +
60 + /**
61 + * File extensions permitted inside an uploaded theme archive.
62 + *
63 + * PHP is on the list because the theme format requires it — see
64 + * self::THEME_UPLOAD_CAPABILITY for the control that actually gates the
65 + * upload. The list exists to keep files that could re-configure the web
66 + * server (.htaccess, web.config, php.ini, .user.ini) out of the uploads
67 + * directory, since those would undo the guards written by
68 + * self::protect_upload_dir().
69 + *
70 + * @since 4.7.3
71 + *
72 + * @var array
73 + */
74 + const ALLOWED_THEME_FILE_EXTENSIONS = array(
75 + 'php',
76 + 'json',
77 + 'css',
78 + 'scss',
79 + 'sass',
80 + 'less',
81 + 'js',
82 + 'map',
83 + 'png',
84 + 'jpg',
85 + 'jpeg',
86 + 'gif',
87 + 'svg',
88 + 'webp',
89 + 'ico',
90 + 'bmp',
91 + 'woff',
92 + 'woff2',
93 + 'ttf',
94 + 'otf',
95 + 'eot',
96 + 'txt',
97 + 'md',
98 + 'html',
99 + 'htm',
100 + 'xml',
101 + 'po',
102 + 'mo',
103 + 'pot',
104 + );
105 +
106 + /**
107 + * Archive entries that are ignored rather than rejected.
108 + *
109 + * Zips built on macOS and Windows carry this housekeeping alongside the
110 + * theme files. Rejecting an otherwise valid theme because of them would
111 + * be a needless failure.
112 + *
113 + * @since 4.7.3
114 + *
115 + * @var array
116 + */
117 + const IGNORED_THEME_FILES = array(
118 + '.ds_store',
119 + 'thumbs.db',
120 + '.gitkeep',
121 + '.gitignore',
122 + );
123 +
124 + /**
38 125 * Construct method.
39 126 */
40 127 protected function __construct() {
41 128 $this->setup_hooks();
@@ -43,128 +130,227 @@
43 130
44 131 /**
45 132 * To setup action/filter.
46 133 *
47 - * @version 4.0.0
48 - *
134 + * @since 4.0.0
135 + *
49 136 * @return void
50 137 */
51 138 protected function setup_hooks() {
52 - add_action('wp_ajax_rmp_save_theme', array( $this, 'rmp_save_theme' ) );
53 - add_action('admin_post_rmp_upload_theme_file', array( $this, 'rmp_upload_theme' ) );
54 - add_action('wp_ajax_rmp_theme_delete', array( $this, 'rmp_theme_delete' ) );
55 - add_action('wp_ajax_rmp_theme_apply', array( $this, 'rmp_theme_apply' ) );
56 - add_action('wp_ajax_rmp_theme_download', array( $this, 'rmp_theme_download' ) );
139 + add_action( 'wp_ajax_rmp_save_theme', array( $this, 'rmp_save_theme' ) );
140 + add_action( 'admin_post_rmp_upload_theme_file', array( $this, 'rmp_upload_theme' ) );
141 + add_action( 'wp_ajax_rmp_menu_theme_upload', array( $this, 'rmp_theme_upload_from_wizard' ) );
142 + add_action( 'wp_ajax_rmp_theme_delete', array( $this, 'rmp_theme_delete' ) );
143 + add_action( 'wp_ajax_rmp_theme_apply', array( $this, 'rmp_theme_apply' ) );
144 + add_action( 'wp_ajax_rmp_call_theme_api', array( $this, 'update_theme_api_cache' ) );
145 + add_action( 'admin_init', array( $this, 'maybe_protect_upload_dir' ) );
57 146 }
58 147
59 -
60 148 /**
149 + * Writes the uploads-directory guards once per plugin version.
150 + *
151 + * The activation hook does not run when a plugin is updated, so installs
152 + * that already hold uploaded themes would never receive the guards
153 + * otherwise.
154 + *
155 + * @since 4.7.3
156 + *
157 + * @return void
158 + */
159 + public function maybe_protect_upload_dir() {
160 +
161 + if ( RMP_PLUGIN_VERSION === get_option( 'rmp_upload_dir_protected' ) ) {
162 + return;
163 + }
164 +
165 + if ( $this->protect_upload_dir() ) {
166 + update_option( 'rmp_upload_dir_protected', RMP_PLUGIN_VERSION );
167 + }
168 + }
169 +
170 +
171 + /**
61 172 * Function to get the list of pro theme from store.
62 - *
63 - * @since 4.0.0
64 - *
65 - * @return array $pro_themes
66 - */
173 + *
174 + * @since 4.0.0
175 + *
176 + * @return array $pro_themes
177 + */
67 178 public function get_themes_by_api() {
68 - $pro_themes = [];
69 179
70 - //These are older version theme which are not compatible with new version.
71 - $exclude_theme_ids = ['47704','47698','45318'];
180 + // If theme list is cached then access it.
181 + $pro_themes = get_transient( 'rmp_theme_api_response' );
182 + if ( ! empty( $pro_themes ) ) {
183 + return $pro_themes;
184 + }
72 185
73 - $endpoint_url = 'https://responsive.menu/edd-api/v2/products/?category=theme';
74 - $rmp_response = wp_remote_get( $endpoint_url, array( 'sslverify' => false ) );
75 - $rmp_response_body = wp_remote_retrieve_body( $rmp_response );
76 - $rmp_response_body = json_decode( $rmp_response_body, true );
186 + $pro_themes = array();
187 +
188 + // These are older version theme which are not compatible with new version.
189 + $exclude_theme_ids = array( '47704', '47698', '45318' );
190 +
191 + $endpoint_url = 'https://responsive.menu/edd-api/v2/products/?category=themes';
192 + $rmp_response = wp_remote_get( $endpoint_url, array( 'sslverify' => false ) );
193 + $rmp_response_body = wp_remote_retrieve_body( $rmp_response );
194 + $rmp_response_body = json_decode( $rmp_response_body, true );
77 195 if ( ! empty( $rmp_response_body ) && is_array( $rmp_response_body ) ) {
78 196 foreach ( $rmp_response_body['products'] as $key => $product ) {
79 - if ( ! in_array( $product['info']['id'], $exclude_theme_ids ) ) {
197 + if ( ! in_array( $product['info']['id'], $exclude_theme_ids, true ) ) {
80 198 $pro_themes[] = array(
81 - 'name' => $product['info']['title'],
82 - 'preview_url' => $product['info']['thumbnail'],
83 - 'buy_link' => $product['info']['link'],
84 - 'price' => $product['pricing']['amount']
199 + 'name' => $product['info']['title'],
200 + 'slug' => $product['info']['slug'],
201 + 'preview_url' => $product['info']['thumbnail'],
202 + 'demo_link' => ! empty( $product['info']['demo_link'] ) ? $product['info']['demo_link'] : '',
203 + 'buy_link' => $product['info']['link'],
204 + 'price' => $product['pricing']['amount'],
85 205 );
86 206 }
87 207 }
88 208 }
89 209
210 + // Cache the theme response.
211 + set_transient( 'rmp_theme_api_response', $pro_themes, DAY_IN_SECONDS );
212 +
90 213 return $pro_themes;
91 214 }
92 215
93 216 /**
94 217 * Function to apply the theme in the menu.
95 - *
96 - * @since 4.0.0
97 - *
98 - * @return json
99 - */
218 + *
219 + * @since 4.0.0
220 + *
221 + * @return json
222 + */
100 223 public function rmp_theme_apply() {
224 + check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
101 225
102 - check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
226 + if ( ! current_user_can( 'administrator' ) ) {
227 + wp_send_json_error( array( 'message' => __( 'You can not apply themes !', 'responsive-menu' ) ) );
228 + }
103 229
104 - $theme_name = sanitize_text_field( $_POST['theme_name'] );
230 + $theme_name = isset( $_POST['theme_name'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_name'] ) ) : '';
105 231 if ( empty( $theme_name ) ) {
106 - wp_send_json_error( [ 'message' => __( 'Theme Name Missing', 'responsive-menu-pro' ) ] );
107 - }
232 + wp_send_json_error( array( 'message' => esc_html__( 'Theme Name Missing', 'responsive-menu' ) ) );
233 + }
108 234
109 - $theme_type = sanitize_text_field( $_POST['theme_type'] );
110 - $menu_id = sanitize_text_field( $_POST['menu_id'] );
111 - $menu_to_use = sanitize_text_field( $_POST['menu_to_use'] );
235 + $theme_type = isset( $_POST['theme_type'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_type'] ) ) : '';
236 + $menu_id = isset( $_POST['menu_id'] ) ? sanitize_text_field( wp_unslash( $_POST['menu_id'] ) ) : '';
237 + $menu_to_use = isset( $_POST['menu_to_use'] ) ? sanitize_text_field( wp_unslash( $_POST['menu_to_use'] ) ) : '';
112 238
113 239 if ( 'template' === $theme_type ) {
114 240 $theme_option = $this->get_saved_theme_options( $theme_name );
115 241 } else {
116 - $theme_option = $this->get_downloaded_theme_settings( $theme_name );
242 + $theme_option = $this->get_available_theme_settings( $theme_name );
117 243 }
118 244
119 - $theme_option['menu_id'] = $menu_id;
120 - $theme_option['menu_theme'] = $theme_name;
121 - $theme_option['theme_type'] = $theme_type;
245 + $theme_option['menu_id'] = $menu_id;
246 + $theme_option['menu_theme'] = $theme_name;
247 + $theme_option['theme_type'] = $theme_type;
122 248 $theme_option['menu_to_use'] = $menu_to_use;
123 249
124 - update_post_meta( $menu_id, 'rmp_menu_meta' ,$theme_option );
250 + update_post_meta( $menu_id, 'rmp_menu_meta', $theme_option );
125 251
126 252 /**
127 253 * Fires when menu theme applied and options are saved.
128 - *
254 + *
129 255 * @since 4.0.0
130 256 * @param int $menu_id
131 257 */
132 - do_action('rmp_theme_apply', $menu_id );
258 + do_action( 'rmp_theme_apply', $menu_id );
133 259
134 - wp_send_json_error( [ 'message' => __( 'Theme applied', 'responsive-menu-pro' ) ] );
260 + wp_send_json_success( array( 'message' => esc_html__( 'Theme applied', 'responsive-menu' ) ) );
261 + }
135 262
136 - }
263 + /**
264 + * Function to get the theme options from availbale theme.
265 + *
266 + * @since 4.0.0
267 + * @since 4.1.0 Add plugin bundle themes, Rename the function and Check minimum version support.
268 + *
269 + * @return array
270 + */
271 + public function get_available_theme_settings( $theme_name ) {
137 272
138 - public function get_downloaded_theme_settings( $theme_name ) {
139 - $theme_dir_path = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
140 - $theme_dirs = glob( $theme_dir_path . '/*' , GLOB_ONLYDIR );
273 + // Themes from uploads directory.
274 + $theme_dir_path = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
275 + $upload_theme_url = wp_upload_dir()['baseurl'] . '/rmp-menu/themes';
276 + $theme_dirs = glob( $theme_dir_path . '/*', GLOB_ONLYDIR );
141 277
142 - foreach( $theme_dirs as $theme_dir ) {
143 - $config_file = $theme_dir . '/config.json';
278 + // Themes from plugin bundle.
279 + $theme_dirs = array_merge( glob( RMP_PLUGIN_PATH_V4 . '/themes/*', GLOB_ONLYDIR ), $theme_dirs );
280 +
281 + $options = array();
282 + $min_version = '4.0.0';
283 +
284 + global $wp_filesystem;
285 + if ( empty( $wp_filesystem ) ) {
286 + require_once ABSPATH . 'wp-admin/includes/file.php';
287 + }
288 + WP_Filesystem();
289 +
290 + foreach ( $theme_dirs as $theme_dir ) {
291 + $config_file = $theme_dir . '/config.json';
144 292 if ( file_exists( $config_file ) ) {
145 - $config = json_decode( file_get_contents( $config_file ), true);
293 + $config = json_decode( $wp_filesystem->get_contents( $config_file ), true );
146 294 if ( $config['name'] == $theme_name ) {
147 - $options = json_decode( file_get_contents( $theme_dir . '/options.json' ), true);
148 - return $options;
295 + $min_version = ! empty( $config['min_rm_version'] ) ? $config['min_rm_version'] : '4.0.0';
296 + $options = json_decode( $wp_filesystem->get_contents( $theme_dir . '/options.json' ), true );
297 + break;
149 298 }
150 299 }
151 300 }
301 + // Check menu theme minimum version compatibility.
302 + if ( version_compare( RMP_PLUGIN_VERSION, $min_version, '<' ) ) {
303 + wp_send_json_error(
304 + array(
305 + 'message' => sprintf(
306 + '%s required Responsive Menu %s version or higher. Please update the plugin with the latest version.',
307 + $theme_name,
308 + $min_version
309 + ),
310 + )
311 + );
312 + }
152 313
153 - return [];
314 + /**
315 + * Filters the theme setting options.
316 + *
317 + * @since 4.0.1
318 + *
319 + * @param array $option
320 + * @param string $theme_name
321 + */
322 + $options = apply_filters( 'get_available_theme_settings', $options, $theme_name );
323 +
324 + return $options;
154 325 }
155 326
327 + /**
328 + * Function to delete the theme.
329 + *
330 + * @since 4.0.0
331 + * @since 4.1.0 Added condition for active theme.
332 + *
333 + * @return json
334 + */
156 335 public function rmp_theme_delete() {
336 + check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
157 337
158 - check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
338 + if ( ! current_user_can( 'administrator' ) ) {
339 + wp_send_json_error( array( 'message' => __( 'You can not delete themes !', 'responsive-menu' ) ) );
340 + }
159 341
160 - $theme_name = sanitize_text_field( $_POST['theme_name'] );
342 + $theme_name = isset( $_POST['theme_name'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_name'] ) ) : '';
161 343 if ( empty( $theme_name ) ) {
162 - wp_send_json_error( [ 'message' => __( 'Theme Name Missing', 'responsive-menu-pro' ) ] );
163 - }
344 + wp_send_json_error( array( 'message' => esc_html__( 'Theme Name Missing', 'responsive-menu' ) ) );
345 + }
164 346
165 - $theme_type = sanitize_text_field( $_POST['theme_type'] );
166 -
347 + $theme_type = isset( $_POST['theme_type'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_type'] ) ) : '';
348 +
349 + if ( $this->is_active_theme( $theme_name, $theme_type ) ) {
350 + wp_send_json_error( array( 'message' => esc_html__( 'This theme is currently active. Please choose another theme and then try deleting.', 'responsive-menu' ) ) );
351 + }
352 +
167 353 if ( 'template' === $theme_type ) {
168 354 $this->delete_template( $theme_name );
169 355 } else {
170 356 $this->delete_theme_folder( $theme_name );
@@ -169,128 +355,393 @@
169 355 } else {
170 356 $this->delete_theme_folder( $theme_name );
171 357 }
172 358
173 - wp_send_json_success( [ 'message' => __( 'Theme deleted', 'responsive-menu-pro' ) ] );
359 + wp_send_json_success( array( 'message' => esc_html__( 'Theme deleted', 'responsive-menu' ) ) );
360 + }
174 361
362 + /**
363 + * Function to return the theme dir path.
364 + *
365 + * @since 4.0.0
366 + * @since 4.1.0 Added the plugin bundle theme.
367 + *
368 + * @return string
369 + */
370 + public function get_theme_dir( $theme_name ) {
371 +
372 + // Themes from uploads directory.
373 + $upload_theme_url = wp_upload_dir()['baseurl'] . '/rmp-menu/themes';
374 + $theme_dir_path = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
375 + $theme_dirs = glob( $theme_dir_path . '/*', GLOB_ONLYDIR );
376 +
377 + // Themes from plugin bundle.
378 + $theme_dirs = array_merge( glob( RMP_PLUGIN_PATH_V4 . '/themes/*', GLOB_ONLYDIR ), $theme_dirs );
379 + global $wp_filesystem;
380 + if ( empty( $wp_filesystem ) ) {
381 + require_once ABSPATH . 'wp-admin/includes/file.php';
382 + }
383 + WP_Filesystem();
384 + foreach ( $theme_dirs as $theme_dir ) {
385 + $config_file = $theme_dir . '/config.json';
386 + if ( file_exists( $config_file ) ) {
387 + $config = json_decode( $wp_filesystem->get_contents( $config_file ), true );
388 + if ( $config['name'] == $theme_name ) {
389 + return $theme_dir;
390 + }
391 + }
392 + }
393 +
394 + return false;
175 395 }
176 396
177 - public function rmp_theme_download() {
397 + /**
398 + * Function to delete the theme dir.
399 + *
400 + * @since 4.0.0
401 + *
402 + * @return void
403 + */
404 + public function delete_theme_folder( $theme_name ) {
405 + if ( empty( $theme_name ) ) {
406 + return;
407 + }
178 408
179 - check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
409 + $theme_dir = $this->get_theme_dir( $theme_name );
410 + if ( empty( $theme_dir ) ) {
411 + return;
412 + }
180 413
181 - $theme_name = sanitize_text_field( $_POST['theme_name'] );
182 - if ( empty( $theme_name ) ) {
183 - wp_send_json_error( [ 'message' => __( 'Theme Name Missing', 'responsive-menu-pro' ) ] );
184 - }
414 + $this->delete_files( $theme_dir );
415 + }
185 416
186 - $theme_type = sanitize_text_field( $_POST['theme_type'] );
417 + /**
418 + * Function to delete the theme files.
419 + *
420 + * @since 4.0.0
421 + *
422 + * @return void
423 + */
424 + public function delete_files( $dir ) {
425 + foreach ( glob( $dir . '/*' ) as $file ) {
426 + if ( is_dir( $file ) ) {
427 + delete_files( $file );
428 + } else {
429 + unlink( $file );
430 + }
431 + }
432 + rmdir( $dir );
433 + }
187 434
188 - $theme_option = [];
189 - if ( 'template' === $theme_type ) {
190 - $theme_option = $this->get_saved_theme_options( $theme_name );
191 - } else {
192 - $theme = $this->download_zip( $theme_name );
435 + /**
436 + * Function to delete the saved template.
437 + *
438 + * @since 4.0.0
439 + *
440 + * @return boolean
441 + */
442 + public function delete_template( $theme_name ) {
443 + $rmp_themes = get_option( self::$theme_option );
444 +
445 + if ( empty( $rmp_themes ) ) {
446 + return false;
193 447 }
194 448
195 - $theme_options_json = json_encode( $theme_option );
449 + foreach ( $rmp_themes as $theme_key => $options ) {
450 + if ( $theme_name === $theme_key ) {
451 + unset( $rmp_themes[ $theme_key ] );
452 + update_option( self::$theme_option, $rmp_themes );
453 + return true;
454 + }
455 + }
196 456
197 - wp_send_json_success( $theme_options_json );
457 + return false;
198 458 }
199 459
200 - public function prepare_theme_zip_file( $theme_name, $options ) {
201 - $zip_file_name = $theme_name . '.zip';
202 -
203 - $zip = new ZipArchive();
460 + /**
461 + * Returns the directory uploaded menu themes are extracted into.
462 + *
463 + * @since 4.7.3
464 + *
465 + * @return string Trailing-slashed absolute path.
466 + */
467 + public function get_theme_upload_dir() {
468 + return trailingslashit( wp_upload_dir()['basedir'] ) . 'rmp-menu/themes/';
469 + }
204 470
205 - if ( $zip->open( $zip_file_name ) === TRUE ) {
206 - $zip->addFile( '/path/to/index.txt', 'newname.txt' );
207 - $zip->close();
208 - } else {
209 - echo 'failed';
471 + /**
472 + * Writes the hardening guards into the plugin's uploads directory.
473 + *
474 + * Menu themes legitimately contain a PHP file, and that file is meant to
475 + * be loaded by the plugin — never requested over HTTP. This drops an
476 + * .htaccess that refuses to serve or execute scripts under
477 + * uploads/rmp-menu/, plus a silent index.php so the directory cannot be
478 + * browsed. Stylesheets and theme images keep working because only script
479 + * types are denied, not the whole directory.
480 + *
481 + * Both files are written only when missing, so a host that has customised
482 + * them is left alone.
483 + *
484 + * Note: .htaccess is honoured by Apache and LiteSpeed only. nginx has no
485 + * per-directory config, so those installs need the equivalent `location`
486 + * rule in the server configuration — see readme.txt.
487 + *
488 + * @since 4.7.3
489 + *
490 + * @return bool True when both guards are in place.
491 + */
492 + public function protect_upload_dir() {
493 +
494 + global $wp_filesystem;
495 +
496 + if ( empty( $wp_filesystem ) ) {
497 + require_once ABSPATH . 'wp-admin/includes/file.php';
210 498 }
499 +
500 + WP_Filesystem();
501 +
502 + if ( empty( $wp_filesystem ) ) {
503 + return false;
504 + }
505 +
506 + $base_dir = trailingslashit( wp_upload_dir()['basedir'] ) . 'rmp-menu/';
507 +
508 + if ( ! $wp_filesystem->is_dir( $base_dir ) && ! wp_mkdir_p( $base_dir ) ) {
509 + return false;
510 + }
511 +
512 + $htaccess = $base_dir . '.htaccess';
513 +
514 + if ( ! $wp_filesystem->exists( $htaccess ) ) {
515 + $rules = "# Responsive Menu: never serve or execute scripts from this directory.\n"
516 + . "<IfModule mod_php.c>\n\tphp_flag engine off\n</IfModule>\n"
517 + . "<IfModule mod_php7.c>\n\tphp_flag engine off\n</IfModule>\n"
518 + . "<IfModule mod_php8.c>\n\tphp_flag engine off\n</IfModule>\n"
519 + . "<FilesMatch \"\\.(?i:php|php[0-9]|phps|phtml|pht|phar|inc|hphp|cgi|pl|py|sh)$\">\n"
520 + . "\t<IfModule mod_authz_core.c>\n\t\tRequire all denied\n\t</IfModule>\n"
521 + . "\t<IfModule !mod_authz_core.c>\n\t\tOrder allow,deny\n\t\tDeny from all\n\t</IfModule>\n"
522 + . "</FilesMatch>\n";
523 +
524 + $wp_filesystem->put_contents( $htaccess, $rules, FS_CHMOD_FILE );
525 + }
526 +
527 + $index = $base_dir . 'index.php';
528 +
529 + if ( ! $wp_filesystem->exists( $index ) ) {
530 + $wp_filesystem->put_contents( $index, "<?php\n// Silence is golden.\n", FS_CHMOD_FILE );
531 + }
532 +
533 + return $wp_filesystem->exists( $htaccess ) && $wp_filesystem->exists( $index );
211 534 }
212 535
213 - public function download_zip( $theme_name ) {
536 + /**
537 + * Returns the list of entry names held in a zip archive.
538 + *
539 + * Opening the archive is also how the upload is confirmed to be a real
540 + * zip: anything that is not one fails to open here, which is a stronger
541 + * check than trusting the uploaded file name.
542 + *
543 + * Mirrors the readers unzip_file() itself uses, so an archive that lists
544 + * here is one that will extract.
545 + *
546 + * @since 4.7.3
547 + *
548 + * @param string $file Absolute path to the archive.
549 + *
550 + * @return array|\WP_Error Entry names, or WP_Error when the file is not a readable zip.
551 + */
552 + protected function get_archive_file_list( $file ) {
214 553
215 - $theme_dir = $this->get_theme_dir( $theme_name );
554 + $error = new \WP_Error(
555 + 'rmp_invalid_archive',
556 + esc_html__( 'This file could not be read as a zip archive.', 'responsive-menu' )
557 + );
216 558
217 - if ( empty( $theme_dir ) ) {
218 - return;
219 - }
559 + $entries = array();
220 560
221 - $theme_root = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
561 + if ( class_exists( 'ZipArchive' ) ) {
562 + $zip = new \ZipArchive();
222 563
223 - // Filename for a zip package
224 - $file_name = strtolower ( preg_replace('/\s+/', '-', $theme_name ) ) . '.zip';
225 - $zip_file = $theme_root.'/'.$file_name;
564 + if ( true !== $zip->open( $file ) ) {
565 + return $error;
566 + }
226 567
227 - $zip = new \ZipArchive();
228 - if ( $zip->open( $zip_file , \ZipArchive::CREATE | \ZipArchive::OVERWRITE ) ) {
568 + for ( $index = 0; $index < $zip->numFiles; $index++ ) {
569 + $entry = $zip->statIndex( $index );
229 570
230 - foreach ( glob( $theme_dir . "/*" ) as $file) {
231 - $zip->addFile($file);
571 + if ( false !== $entry ) {
572 + $entries[] = $entry['name'];
573 + }
232 574 }
233 575
234 576 $zip->close();
577 +
578 + return $entries;
235 579 }
236 580
237 - if ( file_exists( $zip_file ) ) {
238 - header('Content-Type: application/zip');
239 - header('Content-Disposition: attachment; filename="'.basename( $zip_file ).'"');
240 - header('Content-Length: ' . filesize($zip_file));
581 + require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
582 +
583 + $archive = new \PclZip( $file );
584 + $contents = $archive->listContent();
585 +
586 + if ( ! is_array( $contents ) ) {
587 + return $error;
241 588 }
589 +
590 + foreach ( $contents as $entry ) {
591 + $entries[] = $entry['filename'];
592 + }
593 +
594 + return $entries;
242 595 }
243 596
244 - public function get_theme_dir( $theme_name ) {
597 + /**
598 + * Returns the archive entries that a theme is not allowed to contain.
599 + *
600 + * @since 4.7.3
601 + *
602 + * @param array $entries Entry names from the archive.
603 + *
604 + * @return array Offending entry names.
605 + */
606 + protected function get_disallowed_theme_files( $entries ) {
245 607
246 - $theme_dir_path = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
247 - $theme_dirs = glob( $theme_dir_path . '/*' , GLOB_ONLYDIR );
608 + $disallowed = array();
248 609
249 - foreach( $theme_dirs as $theme_dir ) {
250 - $config_file = $theme_dir . '/config.json';
251 - if ( file_exists( $config_file ) ) {
252 - $config = json_decode( file_get_contents( $config_file ), true);
253 - if ( $config['name'] == $theme_name ) {
254 - return $theme_dir;
255 - }
610 + foreach ( $entries as $entry ) {
611 +
612 + // Directories carry no payload of their own.
613 + if ( '/' === substr( $entry, -1 ) ) {
614 + continue;
256 615 }
616 +
617 + // Editor and OS metadata that is harmless but common in theme zips.
618 + if ( 0 === strpos( $entry, '__MACOSX/' ) ) {
619 + continue;
620 + }
621 +
622 + $basename = basename( $entry );
623 +
624 + if ( in_array( strtolower( $basename ), self::IGNORED_THEME_FILES, true ) ) {
625 + continue;
626 + }
627 +
628 + /*
629 + * unzip_file() drops traversing entries itself, but a theme has no
630 + * reason to carry one, so treat it as a rejected upload rather than
631 + * a silently skipped file.
632 + */
633 + if ( 0 !== validate_file( $entry ) || '/' === substr( $entry, 0, 1 ) ) {
634 + $disallowed[] = $entry;
635 + continue;
636 + }
637 +
638 + $extension = strtolower( pathinfo( $basename, PATHINFO_EXTENSION ) );
639 +
640 + // Files with no extension cannot be handed to an interpreter.
641 + if ( '' === $extension ) {
642 + continue;
643 + }
644 +
645 + if ( ! in_array( $extension, self::ALLOWED_THEME_FILE_EXTENSIONS, true ) ) {
646 + $disallowed[] = $entry;
647 + }
257 648 }
258 - return false;
649 +
650 + return $disallowed;
259 651 }
260 652
261 - public function delete_theme_folder( $theme_name ) {
653 + /**
654 + * Validates and extracts an uploaded menu theme archive.
655 + *
656 + * Shared by the settings-page upload and the setup-wizard upload so both
657 + * entry points enforce the same rules.
658 + *
659 + * @since 4.7.3
660 + *
661 + * @return true|\WP_Error True on success, WP_Error describing the refusal otherwise.
662 + */
663 + protected function process_theme_upload() {
262 664
263 - if ( empty( $theme_name ) ) {
264 - return;
665 + if ( ! current_user_can( self::THEME_UPLOAD_CAPABILITY ) ) {
666 + return new \WP_Error(
667 + 'rmp_theme_upload_forbidden',
668 + esc_html__( 'You can not upload themes !', 'responsive-menu' )
669 + );
265 670 }
266 671
267 - $theme_dir = $this->get_theme_dir( $theme_name );
268 - if ( empty( $theme_dir ) ) {
269 - return;
672 + $tmp_name = isset( $_FILES['file']['tmp_name'] ) ? sanitize_text_field( wp_unslash( $_FILES['file']['tmp_name'] ) ) : '';
673 +
674 + if ( empty( $tmp_name ) || ! is_uploaded_file( $tmp_name ) ) {
675 + return new \WP_Error(
676 + 'rmp_theme_upload_missing',
677 + esc_html__( 'Please add zip file !', 'responsive-menu' )
678 + );
270 679 }
271 680
272 - $this->delete_files( $theme_dir );
273 - }
681 + // Reject on the file name first — a cheap check before reading the file.
682 + $file_name = isset( $_FILES['file']['name'] ) ? sanitize_file_name( wp_unslash( $_FILES['file']['name'] ) ) : '';
683 + $file_type = wp_check_filetype( $file_name, array( 'zip' => 'application/zip' ) );
274 684
275 - public function delete_files( $dir ) {
276 - foreach( glob($dir . '/*') as $file) {
277 - if( is_dir($file)) delete_files($file); else unlink($file);
685 + if ( 'zip' !== $file_type['ext'] ) {
686 + return new \WP_Error(
687 + 'rmp_theme_upload_not_zip',
688 + esc_html__( 'Please add zip file !', 'responsive-menu' )
689 + );
278 690 }
279 - rmdir($dir);
280 - }
281 691
282 - public function delete_template( $theme_name ) {
283 - $rmp_themes = get_option( self::$theme_option );
692 + // Reading the archive proves the contents are a zip, not just the name.
693 + $entries = $this->get_archive_file_list( $tmp_name );
284 694
285 - if ( empty( $rmp_themes ) ) {
286 - return false;
695 + if ( is_wp_error( $entries ) ) {
696 + return $entries;
287 697 }
288 698
289 - foreach( $rmp_themes as $theme_key => $options ) {
290 - if ( $theme_name == $theme_key ) {
291 - unset( $rmp_themes[$theme_key] );
292 - update_option( self::$theme_option , $rmp_themes );
699 + $disallowed = $this->get_disallowed_theme_files( $entries );
700 +
701 + if ( ! empty( $disallowed ) ) {
702 + return new \WP_Error(
703 + 'rmp_theme_upload_disallowed_file',
704 + sprintf(
705 + /* translators: %s: comma separated list of file names. */
706 + esc_html__( 'This theme was not installed because it contains files that are not allowed: %s', 'responsive-menu' ),
707 + esc_html( implode( ', ', array_slice( $disallowed, 0, 5 ) ) )
708 + )
709 + );
710 + }
711 +
712 + if ( ! $this->archive_has_theme_config( $entries ) ) {
713 + return new \WP_Error(
714 + 'rmp_theme_upload_not_a_theme',
715 + esc_html__( 'This zip does not look like a menu theme — no config.json was found inside it.', 'responsive-menu' )
716 + );
717 + }
718 +
719 + // Make sure the guards exist before anything is written next to them.
720 + $this->protect_upload_dir();
721 +
722 + $unzipped = unzip_file( $tmp_name, $this->get_theme_upload_dir() );
723 +
724 + if ( is_wp_error( $unzipped ) ) {
725 + return $unzipped;
726 + }
727 +
728 + return true;
729 + }
730 +
731 + /**
732 + * Checks that an archive carries a theme manifest.
733 + *
734 + * @since 4.7.3
735 + *
736 + * @param array $entries Entry names from the archive.
737 + *
738 + * @return bool
739 + */
740 + protected function archive_has_theme_config( $entries ) {
741 +
742 + foreach ( $entries as $entry ) {
743 + if ( 'config.json' === basename( $entry ) ) {
293 744 return true;
294 745 }
295 746 }
296 747
@@ -296,98 +747,168 @@
296 747
297 748 return false;
298 749 }
299 750
751 + /**
752 + * Funtion to upload the menu theme zip file.
753 + *
754 + * @since 4.0.0
755 + * @since 4.0.4 Added nonce and user capabilities check.
756 + * @since 4.7.3 Validates the archive contents and requires `install_plugins`.
757 + *
758 + * @since array $status
759 + */
300 760 public function rmp_upload_theme() {
301 761
302 - status_header(200);
762 + // Check nonce to verify the authenticate upload file.
763 + check_ajax_referer( 'rmp_nonce', 'rmp_theme_upload_nonce' );
303 764
304 - $theme = $_FILES['file']['tmp_name'];
305 -
306 - WP_Filesystem();
307 - $upload_dir = wp_upload_dir()['basedir'] . '/rmp-menu/themes/';
765 + status_header( 200 );
308 766
309 - $unzip_file = unzip_file( $theme , $upload_dir );
767 + $uploaded = $this->process_theme_upload();
310 768
311 - if ( is_wp_error( $unzip_file ) ) {
312 - $status = ['danger' => $unzip_file->get_error_message() ];
313 - } else {
314 - $status = [ 'success' => 'Theme Imported Successfully.'];
769 + if ( is_wp_error( $uploaded ) ) {
770 + wp_send_json_error(
771 + array( 'message' => $uploaded->get_error_message() )
772 + );
315 773 }
316 774
317 - return $status;
775 + wp_send_json_success(
776 + array( 'message' => esc_html__( 'Theme Imported Successfully.', 'responsive-menu' ) )
777 + );
318 778 }
319 779
780 + /**
781 + * Returns the theme list with meta info.
782 + *
783 + * @since 4.0.0
784 + * @since 4.1.0 Added bundle themes.
785 + *
786 + * @return array $theme
787 + */
788 + public function get_themes_from_uploads() {
320 789
321 - public function get_themes_from_uploads() {
790 + // Get theme from uploads directory.
791 + $upload_dir = wp_upload_dir();
792 + $theme_url = $upload_dir['baseurl'] . '/rmp-menu/themes';
793 + $theme_dir_path = $upload_dir['basedir'] . '/rmp-menu/themes';
794 + $theme_dirs = glob( $theme_dir_path . '/*', GLOB_ONLYDIR );
322 795
323 - $theme_url = wp_upload_dir()['baseurl'] . '/rmp-menu/themes';
324 - $theme_dir_path = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
325 - $theme_dirs = glob( $theme_dir_path . '/*' , GLOB_ONLYDIR );
796 + // Get themes from plugin bundle.
797 + $theme_dirs = array_merge( glob( RMP_PLUGIN_PATH_V4 . '/themes/*', GLOB_ONLYDIR ), $theme_dirs );
798 + global $wp_filesystem;
799 + if ( empty( $wp_filesystem ) ) {
800 + require_once ABSPATH . 'wp-admin/includes/file.php';
801 + }
802 + WP_Filesystem();
803 + $themes = array();
804 + foreach ( $theme_dirs as $theme_dir ) {
805 + $config_file = $theme_dir . '/config.json';
806 + $theme_preview_url = $theme_url . '/' . basename( $theme_dir ) . '/preview.png';
326 807
327 - $themes = [];
808 + // Theme preview image from plugin bundle.
809 + if ( ! strpos( $theme_dir, 'uploads' ) ) {
810 + $theme_preview_url = plugin_dir_url( $config_file ) . '/preview.png';
811 + }
328 812
329 - foreach( $theme_dirs as $theme_dir ) {
330 - $config_file = $theme_dir . '/config.json';
331 813 if ( file_exists( $config_file ) ) {
332 - $config = json_decode( file_get_contents( $config_file ), true);
333 - $themes[basename($theme_dir)]['theme_name'] = $config['name'];
334 - $themes[basename($theme_dir)]['theme_version'] = $config['version'];
335 - $themes[basename($theme_dir)]['status'] = ! empty( $config['is_paid'] ) ? 'Pro' : 'Free';
336 - $themes[basename($theme_dir)]['theme_preview_url'] = $theme_url .'/'. basename($theme_dir) . '/preview.png';
814 + $config = json_decode( $wp_filesystem->get_contents( $config_file ), true );
815 + $themes[ basename( $theme_dir ) ]['theme_name'] = $config['name'];
816 + $themes[ basename( $theme_dir ) ]['theme_version'] = $config['version'];
817 + $themes[ basename( $theme_dir ) ]['demo_link'] = ! empty( $config['demo_link'] ) ? $config['demo_link'] : '';
818 + $themes[ basename( $theme_dir ) ]['theme_preview_url'] = $theme_preview_url;
337 819 }
338 820 }
339 821
340 - return $themes;
822 + return $themes;
341 823 }
342 824
343 - public function rmp_save_theme() {
825 + /**
826 + * Returns the theme dir list to supress the theme which are in downloaded list.
827 + *
828 + * @since 4.0.2
829 + *
830 + * @return array $theme_dirs
831 + */
832 + public function get_uploaded_theme_dir() {
833 + $themes = $this->get_themes_from_uploads();
344 834
835 + if ( empty( $themes ) ) {
836 + return;
837 + }
838 +
839 + $theme_dirs = array();
840 +
841 + foreach ( $themes as $theme => $theme_meta ) {
842 +
843 + // Replace the these older themes dir name as slug.
844 + if ( 'electric blue theme' === $theme ) {
845 + $theme_dirs[] = 'electric-blue-free';
846 + } elseif ( 'full-width-theme' === $theme ) {
847 + $theme_dirs[] = 'full-width-free';
848 + } elseif ( 'simple-red-theme' === $theme ) {
849 + $theme_dirs[] = 'simple-red-free';
850 + } else {
851 + $theme_dirs[] = strtolower( $theme );
852 + }
853 + }
854 +
855 + return $theme_dirs;
856 + }
857 +
858 + public function rmp_save_theme() {
345 859 check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
346 860
347 - $theme_name = sanitize_text_field( $_POST['theme_name'] );
861 + $theme_name = isset( $_POST['theme_name'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_name'] ) ) : '';
348 862 if ( empty( $theme_name ) ) {
349 - wp_send_json_error( [ 'message' => __( 'Theme Name Missing', 'responsive-menu-pro' ) ] );
350 - }
863 + wp_send_json_error( array( 'message' => esc_html__( 'Theme Name Missing', 'responsive-menu' ) ) );
864 + }
351 865
352 - $menu_id = sanitize_text_field( $_POST['menu_id'] );
866 + $menu_id = isset( $_POST['menu_id'] ) ? sanitize_text_field( wp_unslash( $_POST['menu_id'] ) ) : '';
353 867 if ( empty( $menu_id ) ) {
354 - wp_send_json_error(
355 - [ 'message' => __( 'Menu ID missing !', 'responsive-menu-pro' )]);
868 + wp_send_json_error(
869 + array( 'message' => esc_html__( 'Menu ID missing !', 'responsive-menu' ) )
870 + );
356 871 }
357 872
358 - $options = array();
359 - parse_str( $_POST['form'], $options );
360 - $options = $options['menu'];
361 -
362 - foreach( $options['mega_menu'] as $key ) {
363 - $options['mega_menu_item'][$key] = get_post_meta( $menu_id, '_rmp_mega_menu_' . $key );
873 + if ( ! current_user_can( 'edit_post', $menu_id ) ) {
874 + wp_send_json_error( array( 'message' => __( 'You can not edit menu !', 'responsive-menu' ) ) );
364 875 }
365 876
366 - unset( $options['mega_menu'] );
877 + $options = array();
878 + $form_data = isset( $_POST['form'] ) ? rm_sanitize_rec_array( wp_unslash( $_POST['form'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
879 + wp_parse_str( $form_data, $options );
880 + $options = $options['menu'];
367 881
368 882 $rmp_themes = get_option( self::$theme_option );
883 +
884 + /**
885 + * Reset to an empty array when the stored option is missing or corrupt.
886 + * Without this, a scalar option value makes the write below a fatal
887 + * error on PHP 8: "Cannot use a scalar value as an array".
888 + */
369 889 if ( empty( $rmp_themes ) || ! is_array( $rmp_themes ) ) {
370 - $rmp_theme = [];
890 + $rmp_themes = array();
371 891 }
372 892
373 - $rmp_themes[$theme_name] = $options;
893 + $rmp_themes[ $theme_name ] = $options;
374 894
375 - update_option( self::$theme_option , $rmp_themes );
895 + update_option( self::$theme_option, $rmp_themes );
376 896
377 897 $data = $this->saved_theme_list();
378 898
899 + wp_send_json_success(
900 + array(
901 + 'themes' => $data,
902 + 'message' => $theme_name . ' is saved',
903 + )
904 + );
379 905
380 - wp_send_json_success( ['themes' => $data , 'message' => $theme_name . ' is saved' ] );
381 -
382 906 exit();
383 -
384 -
385 907 }
386 908
387 909
388 910 public function saved_theme_list() {
389 -
390 911 $rmp_themes = get_option( self::$theme_option );
391 912
392 913 if ( empty( $rmp_themes ) ) {
393 914 return;
@@ -392,10 +913,10 @@
392 913 if ( empty( $rmp_themes ) ) {
393 914 return;
394 915 }
395 916
396 - $theme_list = [];
397 - foreach( $rmp_themes as $theme_name => $options ) {
917 + $theme_list = array();
918 + foreach ( $rmp_themes as $theme_name => $options ) {
398 919 $theme_list[] = $theme_name;
399 920 }
400 921
401 922 return $theme_list;
@@ -401,10 +922,8 @@
401 922 return $theme_list;
402 923 }
403 924
404 925 public function get_saved_theme_options( $theme_name ) {
405 -
406 -
407 926 $rmp_themes = get_option( self::$theme_option );
408 927
409 928 if ( empty( $rmp_themes ) ) {
410 929 return;
@@ -409,126 +928,183 @@
409 928 if ( empty( $rmp_themes ) ) {
410 929 return;
411 930 }
412 931
413 - foreach( $rmp_themes as $theme_key => $options ) {
414 - if( $theme_name == $theme_key ) {
932 + foreach ( $rmp_themes as $theme_key => $options ) {
933 + if ( $theme_name === $theme_key ) {
415 934 return $options;
416 935 }
417 936 }
418 937
419 - return [];
938 + return array();
420 939 }
421 940
422 - public function rmp_saves_theme_list_html() {
423 -
941 + /**
942 + * Function to return the list of saved template themes.
943 + *
944 + * @since 4.0.0
945 + * @since Updated the funtion to add the condition
946 + *
947 + * @return HTML|string
948 + */
949 + public function rmp_saves_theme_template_list( $in_customizer = false ) {
424 950 $rmp_themes = $this->saved_theme_list();
425 951
952 + // Check the list is empty or not.
426 953 if ( empty( $rmp_themes ) ) {
427 - return;
954 + ?><div class="rmp-theme-page-empty">
955 + <span class="rmp-menu-library-blank-icon dashicons dashicons-welcome-widgets-menus"></span>
956 + <h3 class="rmp-menu-library-title"> <?php esc_html_e( 'You have no template !', 'responsive-menu' ); ?> </h3>
957 + </div>
958 + <?php
959 + return;
428 960 }
429 961
430 - $html = '';
431 - foreach( $rmp_themes as $theme_name ) {
432 - $html .= sprintf(
433 - '<div class="rmp-theme-title ">
434 - <span class="item-title"> %1$s </span>
435 - <span class="item-controls">
436 - <a theme-name="%1$s" class="rmp-theme-apply" theme-type="template">Apply</a>
437 - </span>
438 - </div>',
439 - esc_attr( $theme_name )
440 - );
962 + // Prepare the saved theme list and wrapped into html.
963 + foreach ( $rmp_themes as $theme_name ) {
964 + ?>
965 + <div class="rmp-theme-title ">
966 + <span class="item-title"> <?php echo esc_attr( $theme_name ); ?> </span>
967 + <span class="item-controls">
968 + <?php
969 + if ( $in_customizer ) {
970 + ?>
971 + <a theme-name="<?php echo esc_attr( $theme_name ); ?>" class="rmp-theme-apply" theme-type="template"><?php esc_html_e( 'Apply', 'responsive-menu' ); ?></a>
972 + <?php
973 + } else {
974 + ?>
975 + <input type="radio" class="rmp-theme-option" name="menu_theme" id="<?php echo esc_attr( $theme_name ); ?>" value="<?php echo esc_attr( $theme_name ); ?>" theme-type="template"/>
976 + <label theme-name="<?php echo esc_attr( $theme_name ); ?>" class="rmp-theme-use" for="<?php echo esc_attr( $theme_name ); ?>"><?php esc_html_e( 'Use', 'responsive-menu' ); ?></label>
977 + <?php } ?>
978 + </span>
979 + </div>
980 + <?php
441 981 }
442 -
443 - return $html;
444 982 }
445 983
446 - public function rmp_saved_theme_list_for_new_menu() {
984 + /**
985 + * Design the theme list which are from stored.
986 + *
987 + * @since 4.0.0
988 + * @return HTML|string $html
989 + */
990 + public function get_themes_from_theme_store( $in_customizer = false ) {
991 + $themes = $this->get_themes_by_api();
992 + $uploaded_themes = $this->get_uploaded_theme_dir();
447 993
448 - $rmp_themes = $this->saved_theme_list();
449 -
450 - if ( empty( $rmp_themes ) ) {
451 - return;
994 + if ( empty( $uploaded_themes ) || ! is_array( $uploaded_themes ) ) {
995 + $uploaded_themes = array();
452 996 }
453 997
454 - $html = '';
455 - foreach( $rmp_themes as $theme_name ) {
456 - $html .= sprintf('
457 - <div class="rmp-theme-item">
458 - <input type="radio" class="rmp-theme-option" name="menu_theme" id="%1$s" value="%1$s" theme-type="template"/>
459 - <label class="rmp-theme-title" for="%1$s"> %1$s </label>
460 - </div>',
461 - esc_attr( $theme_name )
462 - );
463 - }
998 + foreach ( $themes as $theme ) {
464 999
465 - return $html;
466 - }
1000 + // Avoid the themes which are already uploaded.
1001 + if ( in_array( strtolower( $theme['slug'] ), $uploaded_themes, true ) ) {
1002 + continue;
1003 + }
467 1004
468 - public function get_themes_from_theme_store( $in_wizard = false ) {
469 - $themes = $this->get_themes_by_api();
470 -
471 - if ( empty( $themes ) && $in_wizard ) {
472 - return __( '<h2>Coming soon..</h2>', 'responsive-menu-pro' );
473 - }
474 -
475 - $html = '';
476 - foreach( $themes as $theme ) {
477 -
478 - $action_label = __( 'BUY NOW','responsive-menu-pro' );
479 - $status = __( 'Pro','responsive-menu-pro' );
480 - if ( 0 == $theme['price'] ) {
481 - $status = __( 'Free','responsive-menu-pro' );
482 - $action_label = __( 'DOWNLOAD','responsive-menu-pro' );
1005 + if ( $in_customizer ) {
1006 + $buy_link = add_query_arg(
1007 + array(
1008 + 'utm_source' => 'plugin',
1009 + 'utm_medium' => 'change_theme_wizard',
1010 + ),
1011 + $theme['buy_link']
1012 + );
1013 + } else {
1014 + $buy_link = add_query_arg(
1015 + array(
1016 + 'utm_source' => 'plugin',
1017 + 'utm_medium' => 'new_menu_wizard',
1018 + ),
1019 + $theme['buy_link']
1020 + );
483 1021 }
484 -
485 - $html .= sprintf(
486 - '<li class="rmp_theme_grid_item">
487 - <div class="rmp-item-card">
488 - <figure class="rmp-item-card_image">
489 - <img src="%1$s" alt="%2$s" loading="lazy"/>
490 - <figcaption class="rmp-item-card_label %3$s">
491 - <span class="dashicons dashicons-star-filled "></span> %3$s
492 - </figcaption>
493 - </figure>
1022 + ?>
1023 + <li class="rmp_theme_grid_item">
1024 + <div class="rmp-item-card">
1025 + <figure class="rmp-item-card_image">
1026 + <img src="<?php echo esc_url( $theme['preview_url'] ); ?>" alt="<?php echo esc_attr( $theme['name'] ); ?>" loading="lazy"/>
1027 + </figure>
1028 + <div class="rmp-item-card-backside">
494 1029 <div class="rmp-item-card_contents">
495 - <h4> %2$s </h4>
1030 + <h4> <?php echo esc_html( $theme['name'] ); ?> </h4>
1031 + </div>
1032 + <div class="rmp-item-card_action">
1033 + <?php
1034 + if ( ! empty( $theme['demo_link'] ) ) {
1035 + if ( $in_customizer ) {
1036 + $link = add_query_arg(
1037 + array(
1038 + 'utm_source' => 'plugin',
1039 + 'utm_medium' => 'change_theme_wizard',
1040 + ),
1041 + $theme['demo_link']
1042 + );
1043 + } else {
1044 + $link = add_query_arg(
1045 + array(
1046 + 'utm_source' => 'plugin',
1047 + 'utm_medium' => 'new_menu_wizard',
1048 + ),
1049 + $theme['demo_link']
1050 + );
1051 + }
1052 + ?>
1053 + <a href="<?php echo esc_url( $link ); ?>" alt="<?php echo esc_attr( $theme['name'] ); ?>" target="_blank" rel="noopener" class="button"><?php esc_html_e( 'View Demo', 'responsive-menu' ); ?></a>
1054 + <?php
1055 + }
1056 + ?>
1057 + <a href="<?php echo esc_url( $buy_link ); ?>" target="_blank" rel="noopener" class="button btn-blue">
1058 + <?php
1059 + if ( 0 === intval( $theme['price'] ) ) {
1060 + esc_html_e( 'Download', 'responsive-menu' );
1061 + } else {
1062 + esc_html_e( 'Purchase', 'responsive-menu' );
1063 + }
1064 + ?>
1065 + </a>
1066 + </div>
496 1067 </div>
497 - <div class="rmp-item-card_action">
498 - <a href="%4$s" target="_blank" class="button %5$s"> %5$s </a>
499 - </div>
500 - </div>
501 - </li>',
502 - esc_url( $theme['preview_url']),
503 - esc_attr( $theme['name'] ),
504 - $status,
505 - esc_url( $theme['buy_link'] ),
506 - $action_label
507 - );
1068 + </div>
1069 + </li>
1070 + <?php
508 1071 }
509 1072
510 - return $html;
1073 + if ( empty( $themes ) ) {
1074 + ?>
1075 + <div class="rmp-theme-page-empty">
1076 + <span class="rmp-menu-library-blank-icon fas fa-file-download"></span>
1077 + <h3 class="rmp-menu-library-title"> <?php esc_html_e( 'No theme available !', 'responsive-menu' ); ?> </h3>
1078 + </div>
1079 + <?php
1080 + }
511 1081 }
512 1082
513 1083 public function all_theme_combine_list() {
1084 + $all_themes = array();
514 1085
515 - $all_themes = [];
516 -
517 - //Local saved themes.
1086 + // Local saved themes.
518 1087 $themes = $this->saved_theme_list();
519 1088
520 1089 if ( ! empty( $themes ) && is_array( $themes ) ) {
521 - foreach( $themes as $theme ) {
522 - $all_themes[] = [ 'name' => $theme , 'type' => 'Template' ];
1090 + foreach ( $themes as $theme ) {
1091 + $all_themes[] = array(
1092 + 'name' => $theme,
1093 + 'type' => 'Template',
1094 + );
523 1095 }
524 1096 }
525 1097
526 - //Uploaded themes.
1098 + // Uploaded themes.
527 1099 $themes = $this->get_themes_from_uploads();
528 1100 if ( ! empty( $themes ) && is_array( $themes ) ) {
529 - foreach( $themes as $theme ) {
530 - $all_themes[] = [ 'name' => $theme['theme_name'] , 'type' => 'Downloaded', 'preview_url' => $theme['theme_preview_url'] ];
1101 + foreach ( $themes as $theme ) {
1102 + $all_themes[] = array(
1103 + 'name' => $theme['theme_name'],
1104 + 'type' => 'Downloaded',
1105 + 'preview_url' => $theme['theme_preview_url'],
1106 + );
531 1107 }
532 1108 }
533 1109
534 1110 return $all_themes;
@@ -533,40 +1109,460 @@
533 1109
534 1110 return $all_themes;
535 1111 }
536 1112
1113 + /**
1114 + * Returns the thumbnail of theme.
1115 + *
1116 + * @since 4.0.0
1117 + *
1118 + * @return string|url|null
1119 + */
537 1120 public function get_theme_preview_url( $theme_name ) {
538 1121
539 - $theme_url = wp_upload_dir()['baseurl'] . '/rmp-menu/themes';
540 - $theme_dir_path = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
541 - $theme_dirs = glob( $theme_dir_path . '/*' , GLOB_ONLYDIR );
1122 + // Get theme from uploads directory.
1123 + $upload_dir = wp_upload_dir();
1124 + $theme_url = $upload_dir['baseurl'] . '/rmp-menu/themes';
1125 + $theme_dir_path = $upload_dir['basedir'] . '/rmp-menu/themes';
1126 + $theme_dirs = glob( $theme_dir_path . '/*', GLOB_ONLYDIR );
542 1127
543 - foreach( $theme_dirs as $theme_dir ) {
544 - $config_file = $theme_dir . '/config.json';
1128 + // Get themes from plugin bundle.
1129 + $theme_dirs = array_merge( glob( RMP_PLUGIN_PATH_V4 . '/themes/*', GLOB_ONLYDIR ), $theme_dirs );
1130 + global $wp_filesystem;
1131 + if ( empty( $wp_filesystem ) ) {
1132 + require_once ABSPATH . 'wp-admin/includes/file.php';
1133 + }
1134 + WP_Filesystem();
1135 + foreach ( $theme_dirs as $theme_dir ) {
1136 + $config_file = $theme_dir . '/config.json';
1137 + $theme_preview_url = $theme_url . '/' . basename( $theme_dir ) . '/preview.png';
1138 +
1139 + // Theme preview image from plugin bundle.
1140 + if ( ! strpos( $theme_dir, 'uploads' ) ) {
1141 + $theme_preview_url = plugin_dir_url( $config_file ) . '/preview.png';
1142 + }
1143 +
545 1144 if ( file_exists( $config_file ) ) {
546 - $config = json_decode( file_get_contents( $config_file ), true);
1145 + $config = json_decode( $wp_filesystem->get_contents( $config_file ), true );
547 1146 if ( $config['name'] == $theme_name ) {
548 - return $theme_url .'/'. basename($theme_dir) . '/preview.png';
1147 + return $theme_preview_url;
549 1148 }
550 1149 }
551 1150 }
552 - return '';
1151 +
1152 + return;
553 1153 }
554 1154
1155 + /**
1156 + * Function to return the theme thumbnail element.
1157 + *
1158 + * @since 4.0.0
1159 + *
1160 + * @return strinh|HTML|null
1161 + */
555 1162 public function get_theme_thumbnail( $theme_name, $theme_type ) {
556 - if( 'Default' == $theme_name || $theme_type != 'downloaded' ) {
557 - return sprintf( '<img src="%s" class="theme-thumbnail">',
558 - esc_url( RMP_PLUGIN_URL_V4 .'/assets/images/no-preview.jpeg' )
1163 +
1164 + // If theme is template
1165 + if ( 'template' === $theme_type ) {
1166 + ?>
1167 + <img src="<?php echo esc_url( RMP_PLUGIN_URL_V4 . '/assets/images/no-preview.jpeg' ); ?>" class="theme-thumbnail" alt="<?php echo esc_attr( $theme_type ); ?>" >
1168 + <?php
1169 + }
1170 +
1171 + // If theme is default.
1172 + if ( 'default' === $theme_type ) {
1173 + ?>
1174 + <img src="<?php echo esc_url( esc_url( $this->theme_preview_img ) ); ?>" class="theme-thumbnail" alt="<?php echo esc_attr( $theme_type ); ?>" >
1175 + <?php
1176 + }
1177 +
1178 + $theme_preview_url = $this->get_theme_preview_url( $theme_name );
1179 + if ( empty( $theme_preview_url ) ) {
1180 + return;
1181 + }
1182 + ?>
1183 + <img src="<?php echo esc_url( $theme_preview_url ); ?>" class="theme-thumbnail" alt="<?php echo esc_attr( $theme_type ); ?>" >
1184 + <?php
1185 + }
1186 +
1187 + /**
1188 + * Returns the theme index file path.
1189 + *
1190 + * The index is read from a theme's own config.json, which for an uploaded
1191 + * theme is attacker-supplied, and the caller require_once's whatever comes
1192 + * back. It is therefore reduced to a file name inside the theme directory.
1193 + *
1194 + * @since 4.1.0
1195 + * @since 4.7.3 Constrained the configured index to a PHP file in the theme directory.
1196 + *
1197 + * @return string;
1198 + */
1199 + public function get_theme_index_file( $theme_name ) {
1200 +
1201 + // Get theme from uploads directory.
1202 + $theme_url = wp_upload_dir()['baseurl'] . '/rmp-menu/themes';
1203 + $theme_dir_path = wp_upload_dir()['basedir'] . '/rmp-menu/themes';
1204 + $theme_dirs = glob( $theme_dir_path . '/*', GLOB_ONLYDIR );
1205 +
1206 + // Get themes from plugin bundle.
1207 + $theme_dirs = array_merge( glob( RMP_PLUGIN_PATH_V4 . '/themes/*', GLOB_ONLYDIR ), $theme_dirs );
1208 +
1209 + global $wp_filesystem;
1210 + if ( empty( $wp_filesystem ) ) {
1211 + require_once ABSPATH . 'wp-admin/includes/file.php';
1212 + }
1213 + WP_Filesystem();
1214 +
1215 + foreach ( $theme_dirs as $theme_dir ) {
1216 +
1217 + $config_file = $theme_dir . '/config.json';
1218 +
1219 + if ( file_exists( $config_file ) ) {
1220 + $config = json_decode( $wp_filesystem->get_contents( $config_file ), true );
1221 +
1222 + if ( empty( $config['name'] ) || empty( $config['index'] ) || $config['name'] !== $theme_name ) {
1223 + continue;
1224 + }
1225 +
1226 + // Never let the manifest point outside its own directory.
1227 + $index_file = basename( $config['index'] );
1228 +
1229 + if ( 'php' !== strtolower( pathinfo( $index_file, PATHINFO_EXTENSION ) ) ) {
1230 + continue;
1231 + }
1232 +
1233 + return $theme_dir . '/' . $index_file;
1234 + }
1235 + }
1236 +
1237 + return;
1238 + }
1239 +
1240 + /**
1241 + * Returns all uploaded theme list.
1242 + *
1243 + * @since 4.1.0
1244 + *
1245 + * @return array
1246 + */
1247 + public function get_menu_active_themes() {
1248 + $active_themes = array();
1249 + $themes = $this->get_themes_from_uploads();
1250 + foreach ( $themes as $key => $theme ) {
1251 + if ( empty( $theme['theme_name'] ) ) {
1252 + continue;
1253 + }
1254 +
1255 + $active_themes[ $key ] = $theme['theme_name'];
1256 + }
1257 +
1258 + return $active_themes;
1259 + }
1260 +
1261 + /**
1262 + * Check theme is active or not.
1263 + *
1264 + * @since 4.1.0
1265 + *
1266 + * @return bool
1267 + */
1268 + public function is_active_theme( $theme_name, $theme_type ) {
1269 + if ( empty( $theme_name ) || empty( $theme_type ) ) {
1270 + return false;
1271 + }
1272 +
1273 + $option_manager = Option_Manager::get_instance();
1274 + $menu_ids = get_all_rmp_menu_ids();
1275 +
1276 + foreach ( $menu_ids as $menu_id ) {
1277 + $options = $option_manager->get_options( $menu_id );
1278 +
1279 + if ( empty( $options['menu_theme'] ) || empty( $options['theme_type'] ) ) {
1280 + continue;
1281 + }
1282 +
1283 + if ( $options['menu_theme'] === $theme_name && $options['theme_type'] === $theme_type ) {
1284 + return true;
1285 + }
1286 + }
1287 +
1288 + return false;
1289 + }
1290 +
1291 + /**
1292 + * Function to returns the available theme list.
1293 + *
1294 + * @since 4.1.0
1295 + * @return HTML|string $html
1296 + */
1297 + public function get_available_themes( $in_customizer = false ) {
1298 + ?>
1299 + <ul class="rmp_theme_grids">
1300 + <?php
1301 +
1302 + if ( ! $in_customizer ) {
1303 + ?>
1304 + <li class="rmp_theme_grid_item">
1305 + <input type="radio" checked id="default" class="rmp-theme-option" name="menu_theme" value="" theme-type="default"/>
1306 + <label class="rmp-item-card default-item" for="default">
1307 + <figure class="rmp-item-card_image">
1308 + <img src="<?php echo esc_url( esc_url( $this->theme_preview_img ) ); ?>" alt="<?php esc_html_e( 'Default Theme', 'responsive-menu' ); ?>" loading="lazy"/>
1309 + </figure>
1310 + <div class="rmp-item-card-backside">
1311 + <div class="rmp-item-card_contents">
1312 + <h4> <?php esc_html_e( 'Default Theme', 'responsive-menu' ); ?> </h4>
1313 + </div>
1314 + <div class="rmp-item-card_action">
1315 + <a href="https://demo.responsive.menu/themes/default-theme/?utm_source=plugin&utm_medium=new_menu_wizard" alt="<?php esc_html_e( 'Default Theme', 'responsive-menu' ); ?>" target="_blank" rel="noopener" class="button"><?php esc_html_e( 'View Demo', 'responsive-menu' ); ?></a>
1316 + </div>
1317 + </div>
1318 + </label>
1319 + </li>
1320 + <?php
1321 + }
1322 +
1323 + $downloaded_themes = $this->get_themes_from_uploads();
1324 + foreach ( $downloaded_themes as $theme ) {
1325 + $id = 'rmp-theme-' . preg_replace( '/\s+/', '', $theme['theme_name'] );
1326 + ?>
1327 + <li class="rmp_theme_grid_item">
1328 + <?php
1329 + if ( ! $in_customizer ) {
1330 + ?>
1331 + <input type="radio" id="<?php echo esc_attr( $id ); ?>" theme-type="downloaded" class="rmp-theme-option" name="menu_theme" value="<?php echo esc_html( $theme['theme_name'] ); ?>"/>
1332 + <?php
1333 + }
1334 + ?>
1335 + <label class="rmp-item-card" for="<?php echo esc_attr( $id ); ?>">
1336 + <figure class="rmp-item-card_image">
1337 + <img src="<?php echo esc_url( $theme['theme_preview_url'] ); ?>" alt="<?php echo esc_html( $theme['theme_name'] ); ?>" loading="lazy"/>
1338 + </figure>
1339 + <div class="rmp-item-card-backside">
1340 + <div class="rmp-item-card_contents">
1341 + <h4> <?php echo esc_html( $theme['theme_name'] ); ?> </h4>
1342 + </div>
1343 + <div class="rmp-item-card_action">
1344 + <?php
1345 + if ( ! empty( $theme['demo_link'] ) ) {
1346 + if ( $in_customizer ) {
1347 + $link = add_query_arg(
1348 + array(
1349 + 'utm_source' => 'plugin',
1350 + 'utm_medium' => 'change_theme_wizard',
1351 + ),
1352 + $theme['demo_link']
1353 + );
1354 + } else {
1355 + $link = add_query_arg(
1356 + array(
1357 + 'utm_source' => 'plugin',
1358 + 'utm_medium' => 'new_menu_wizard',
1359 + ),
1360 + $theme['demo_link']
1361 + );
1362 + }
1363 + ?>
1364 + <a href="<?php echo esc_url( $link ); ?>" alt="<?php echo esc_attr( $theme['theme_name'] ); ?>" target="_blank" rel="noopener" class="button"><?php esc_html_e( 'View Demo', 'responsive-menu' ); ?></a>
1365 + <?php
1366 + }
1367 + if ( $in_customizer ) {
1368 + ?>
1369 + <button class="button btn-blue rmp-theme-apply" theme-name="<?php echo esc_html( $theme['theme_name'] ); ?>" theme-type="downloaded" ><?php esc_html_e( 'Apply', 'responsive-menu' ); ?></button>
1370 + <?php
1371 + }
1372 + ?>
1373 + </div>
1374 + </div>
1375 + </label>
1376 + </li>
1377 + <?php
1378 + }
1379 + ?>
1380 + </ul>
1381 + <?php
1382 + }
1383 +
1384 + /**
1385 + * Function to returns the available theme list.
1386 + *
1387 + * @since 4.1.0
1388 + * @return HTML|string $html
1389 + */
1390 + public function get_available_themes_return( $in_customizer = false ) {
1391 + $html = '<ul class="rmp_theme_grids">';
1392 +
1393 + if ( ! $in_customizer ) {
1394 + $html .= sprintf(
1395 + '<li class="rmp_theme_grid_item">
1396 + <input type="radio" checked id="default" class="rmp-theme-option" name="menu_theme" value="" theme-type="default"/>
1397 + <label class="rmp-item-card default-item" for="default">
1398 + <figure class="rmp-item-card_image">
1399 + <img src="%1$s" alt="%2$s" loading="lazy"/>
1400 + </figure>
1401 + <div class="rmp-item-card-backside">
1402 + <div class="rmp-item-card_contents">
1403 + <h4> %2$s </h4>
1404 + </div>
1405 + <div class="rmp-item-card_action">
1406 + <a href="https://demo.responsive.menu/themes/default-theme/?utm_source=plugin&utm_medium=new_menu_wizard" alt="%2$s" target="_blank" rel="noopener" class="button">%3$s</a>
1407 + </div>
1408 + </div>
1409 + </label>
1410 + </li>',
1411 + esc_url( $this->theme_preview_img ),
1412 + esc_html__( 'Default Theme', 'responsive-menu' ),
1413 + esc_html__( 'View Demo', 'responsive-menu' )
559 1414 );
560 - } else {
561 - $theme_url = $this->get_theme_preview_url( $theme_name );
562 - return sprintf( '<img src="%s" class="theme-thumbnail">',
563 - esc_url( $theme_url )
1415 + }
1416 +
1417 + $downloaded_themes = $this->get_themes_from_uploads();
1418 + foreach ( $downloaded_themes as $theme ) {
1419 + $id = 'rmp-theme-' . preg_replace( '/\s+/', '', $theme['theme_name'] );
1420 +
1421 + $demo_link = '';
1422 + if ( ! empty( $theme['demo_link'] ) ) {
1423 + if ( $in_customizer ) {
1424 + $link = add_query_arg(
1425 + array(
1426 + 'utm_source' => 'plugin',
1427 + 'utm_medium' => 'change_theme_wizard',
1428 + ),
1429 + $theme['demo_link']
1430 + );
1431 + } else {
1432 + $link = add_query_arg(
1433 + array(
1434 + 'utm_source' => 'plugin',
1435 + 'utm_medium' => 'new_menu_wizard',
1436 + ),
1437 + $theme['demo_link']
1438 + );
1439 + }
1440 +
1441 + $demo_link = sprintf(
1442 + '<a href="%s" alt="%s" target="_blank" rel="noopener" class="button">%s</a>',
1443 + esc_url( $link ),
1444 + esc_attr( $theme['theme_name'] ),
1445 + esc_html__( 'View Demo', 'responsive-menu' )
1446 + );
1447 + }
1448 +
1449 + $select_option = $apply_button = '';
1450 + if ( $in_customizer ) {
1451 + $apply_button = sprintf(
1452 + '<button class="button btn-blue rmp-theme-apply" theme-name="%s" theme-type="downloaded" >%s</button>',
1453 + esc_html( $theme['theme_name'] ),
1454 + esc_html__( 'Apply', 'responsive-menu' )
1455 + );
1456 + } else {
1457 + $select_option = sprintf(
1458 + '<input type="radio" id="%1$s" theme-type="downloaded" class="rmp-theme-option" name="menu_theme" value="%2$s"/>',
1459 + esc_attr( $id ),
1460 + esc_html( $theme['theme_name'] )
1461 + );
1462 + }
1463 +
1464 + $html .= sprintf(
1465 + '
1466 + <li class="rmp_theme_grid_item">
1467 + %5$s
1468 + <label class="rmp-item-card" for="%1$s">
1469 + <figure class="rmp-item-card_image">
1470 + <img src="%3$s" alt="%2$s" loading="lazy"/>
1471 + </figure>
1472 + <div class="rmp-item-card-backside">
1473 + <div class="rmp-item-card_contents">
1474 + <h4> %2$s </h4>
1475 + </div>
1476 + <div class="rmp-item-card_action">
1477 + %4$s
1478 + %6$s
1479 + </div>
1480 + </div>
1481 + </label>
1482 + </li>',
1483 + esc_attr( $id ),
1484 + esc_html( $theme['theme_name'] ),
1485 + esc_url( $theme['theme_preview_url'] ),
1486 + $demo_link,
1487 + $select_option,
1488 + $apply_button
564 1489 );
565 1490 }
1491 +
1492 + $html .= '</ul>';
1493 +
1494 + return $html;
566 1495 }
567 1496
568 -}
1497 + /**
1498 + * Function to upload the theme by ajax.
1499 + *
1500 + * @since 4.1.0
1501 + * @since 4.7.3 Validates the archive contents and requires `install_plugins`.
1502 + *
1503 + * @return json
1504 + */
1505 + public function rmp_theme_upload_from_wizard() {
569 1506
1507 + // Check nonce to verify the authenticate upload file.
1508 + check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
570 1509
1510 + // Upload the file in upload directory.
1511 + status_header( 200 );
571 1512
1513 + $uploaded = $this->process_theme_upload();
572 1514
1515 + if ( is_wp_error( $uploaded ) ) {
1516 + wp_send_json_error(
1517 + array( 'message' => $uploaded->get_error_message() )
1518 + );
1519 + }
1520 +
1521 + // Return the response
1522 + wp_send_json_success(
1523 + array(
1524 + 'message' => esc_html__( 'Theme is uploaded successfully', 'responsive-menu' ),
1525 + 'html' => $this->get_available_themes_return( $this->is_customizer() ),
1526 + )
1527 + );
1528 + }
1529 +
1530 + /**
1531 + * Function to update the theme api cached data.
1532 + *
1533 + * @since 4.1.0
1534 + *
1535 + * @return json
1536 + */
1537 + public function update_theme_api_cache() {
1538 +
1539 + // Check nonce to verify the authenticate upload file.
1540 + check_ajax_referer( 'rmp_nonce', 'ajax_nonce' );
1541 +
1542 + return wp_send_json_success(
1543 + array(
1544 + 'message' => esc_html__( 'Cache data updated !', 'responsive-menu' ),
1545 + 'html' => $this->get_themes_from_theme_store( $this->is_customizer() ),
1546 + )
1547 + );
1548 + }
1549 +
1550 + /**
1551 + * Function to check the request origin either from customizer or create menu page.
1552 + *
1553 + * @since 4.1.3
1554 + *
1555 + * @return bool
1556 + */
1557 + public function is_customizer() {
1558 + $is_customizer_request = false;
1559 + if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
1560 + wp_parse_str( wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) )['query'], $params );
1561 + if ( ! empty( $params['action'] ) && ! empty( $params['editor'] ) ) {
1562 + $is_customizer_request = true;
1563 + }
1564 + }
1565 +
1566 + return $is_customizer_request;
1567 + }
1568 +}