| 1 |
<?php |
| 2 |
/** |
| 3 |
* This file contain the Theme_Manager class and it's functionalities for menu. |
| 4 |
* |
| 5 |
* @version 4.0.0 |
| 6 |
* @author Expresstech System |
| 7 |
* |
| 8 |
* @package responsive-menu |
| 9 |
*/ |
| 10 |
|
| 11 |
namespace RMP\Features\Inc; |
| 12 |
|
| 13 |
use RMP\Features\Inc\Traits\Singleton; |
| 14 |
use RMP\Features\Inc\Option_Manager; |
| 15 |
|
| 16 |
// Disable the direct access to this class. |
| 17 |
if ( ! defined( 'ABSPATH' ) ) { |
| 18 |
exit; |
| 19 |
} |
| 20 |
|
| 21 |
/** |
| 22 |
* Class Theme_Manager |
| 23 |
* This class is handling the menu themes and its functionalities. |
| 24 |
* |
| 25 |
* @since 4.0.0 |
| 26 |
*/ |
| 27 |
class Theme_Manager { |
| 28 |
|
| 29 |
use Singleton; |
| 30 |
|
| 31 |
/** |
| 32 |
* This is option key where saved themes are stored. |
| 33 |
* |
| 34 |
* @var string $theme_option |
| 35 |
*/ |
| 36 |
protected static $theme_option = 'rmp_themes'; |
| 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 |
/** |
| 125 |
* Construct method. |
| 126 |
*/ |
| 127 |
protected function __construct() { |
| 128 |
$this->setup_hooks(); |
| 129 |
} |
| 130 |
|
| 131 |
/** |
| 132 |
* To setup action/filter. |
| 133 |
* |
| 134 |
* @since 4.0.0 |
| 135 |
* |
| 136 |
* @return void |
| 137 |
*/ |
| 138 |
protected function setup_hooks() { |
| 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' ) ); |
| 146 |
} |
| 147 |
|
| 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 |
/** |
| 172 |
* Function to get the list of pro theme from store. |
| 173 |
* |
| 174 |
* @since 4.0.0 |
| 175 |
* |
| 176 |
* @return array $pro_themes |
| 177 |
*/ |
| 178 |
public function get_themes_by_api() { |
| 179 |
|
| 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 |
} |
| 185 |
|
| 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 ); |
| 195 |
if ( ! empty( $rmp_response_body ) && is_array( $rmp_response_body ) ) { |
| 196 |
foreach ( $rmp_response_body['products'] as $key => $product ) { |
| 197 |
if ( ! in_array( $product['info']['id'], $exclude_theme_ids, true ) ) { |
| 198 |
$pro_themes[] = array( |
| 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'], |
| 205 |
); |
| 206 |
} |
| 207 |
} |
| 208 |
} |
| 209 |
|
| 210 |
// Cache the theme response. |
| 211 |
set_transient( 'rmp_theme_api_response', $pro_themes, DAY_IN_SECONDS ); |
| 212 |
|
| 213 |
return $pro_themes; |
| 214 |
} |
| 215 |
|
| 216 |
/** |
| 217 |
* Function to apply the theme in the menu. |
| 218 |
* |
| 219 |
* @since 4.0.0 |
| 220 |
* |
| 221 |
* @return json |
| 222 |
*/ |
| 223 |
public function rmp_theme_apply() { |
| 224 |
check_ajax_referer( 'rmp_nonce', 'ajax_nonce' ); |
| 225 |
|
| 226 |
if ( ! current_user_can( 'administrator' ) ) { |
| 227 |
wp_send_json_error( array( 'message' => __( 'You can not apply themes !', 'responsive-menu' ) ) ); |
| 228 |
} |
| 229 |
|
| 230 |
$theme_name = isset( $_POST['theme_name'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_name'] ) ) : ''; |
| 231 |
if ( empty( $theme_name ) ) { |
| 232 |
wp_send_json_error( array( 'message' => esc_html__( 'Theme Name Missing', 'responsive-menu' ) ) ); |
| 233 |
} |
| 234 |
|
| 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'] ) ) : ''; |
| 238 |
|
| 239 |
if ( 'template' === $theme_type ) { |
| 240 |
$theme_option = $this->get_saved_theme_options( $theme_name ); |
| 241 |
} else { |
| 242 |
$theme_option = $this->get_available_theme_settings( $theme_name ); |
| 243 |
} |
| 244 |
|
| 245 |
$theme_option['menu_id'] = $menu_id; |
| 246 |
$theme_option['menu_theme'] = $theme_name; |
| 247 |
$theme_option['theme_type'] = $theme_type; |
| 248 |
$theme_option['menu_to_use'] = $menu_to_use; |
| 249 |
|
| 250 |
update_post_meta( $menu_id, 'rmp_menu_meta', $theme_option ); |
| 251 |
|
| 252 |
/** |
| 253 |
* Fires when menu theme applied and options are saved. |
| 254 |
* |
| 255 |
* @since 4.0.0 |
| 256 |
* @param int $menu_id |
| 257 |
*/ |
| 258 |
do_action( 'rmp_theme_apply', $menu_id ); |
| 259 |
|
| 260 |
wp_send_json_success( array( 'message' => esc_html__( 'Theme applied', 'responsive-menu' ) ) ); |
| 261 |
} |
| 262 |
|
| 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 ) { |
| 272 |
|
| 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 ); |
| 277 |
|
| 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'; |
| 292 |
if ( file_exists( $config_file ) ) { |
| 293 |
$config = json_decode( $wp_filesystem->get_contents( $config_file ), true ); |
| 294 |
if ( $config['name'] == $theme_name ) { |
| 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; |
| 298 |
} |
| 299 |
} |
| 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 |
} |
| 313 |
|
| 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; |
| 325 |
} |
| 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 |
*/ |
| 335 |
public function rmp_theme_delete() { |
| 336 |
check_ajax_referer( 'rmp_nonce', 'ajax_nonce' ); |
| 337 |
|
| 338 |
if ( ! current_user_can( 'administrator' ) ) { |
| 339 |
wp_send_json_error( array( 'message' => __( 'You can not delete themes !', 'responsive-menu' ) ) ); |
| 340 |
} |
| 341 |
|
| 342 |
$theme_name = isset( $_POST['theme_name'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_name'] ) ) : ''; |
| 343 |
if ( empty( $theme_name ) ) { |
| 344 |
wp_send_json_error( array( 'message' => esc_html__( 'Theme Name Missing', 'responsive-menu' ) ) ); |
| 345 |
} |
| 346 |
|
| 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 |
|
| 353 |
if ( 'template' === $theme_type ) { |
| 354 |
$this->delete_template( $theme_name ); |
| 355 |
} else { |
| 356 |
$this->delete_theme_folder( $theme_name ); |
| 357 |
} |
| 358 |
|
| 359 |
wp_send_json_success( array( 'message' => esc_html__( 'Theme deleted', 'responsive-menu' ) ) ); |
| 360 |
} |
| 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; |
| 395 |
} |
| 396 |
|
| 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 |
} |
| 408 |
|
| 409 |
$theme_dir = $this->get_theme_dir( $theme_name ); |
| 410 |
if ( empty( $theme_dir ) ) { |
| 411 |
return; |
| 412 |
} |
| 413 |
|
| 414 |
$this->delete_files( $theme_dir ); |
| 415 |
} |
| 416 |
|
| 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 |
} |
| 434 |
|
| 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; |
| 447 |
} |
| 448 |
|
| 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 |
} |
| 456 |
|
| 457 |
return false; |
| 458 |
} |
| 459 |
|
| 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 |
} |
| 470 |
|
| 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'; |
| 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 ); |
| 534 |
} |
| 535 |
|
| 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 ) { |
| 553 |
|
| 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 |
); |
| 558 |
|
| 559 |
$entries = array(); |
| 560 |
|
| 561 |
if ( class_exists( 'ZipArchive' ) ) { |
| 562 |
$zip = new \ZipArchive(); |
| 563 |
|
| 564 |
if ( true !== $zip->open( $file ) ) { |
| 565 |
return $error; |
| 566 |
} |
| 567 |
|
| 568 |
for ( $index = 0; $index < $zip->numFiles; $index++ ) { |
| 569 |
$entry = $zip->statIndex( $index ); |
| 570 |
|
| 571 |
if ( false !== $entry ) { |
| 572 |
$entries[] = $entry['name']; |
| 573 |
} |
| 574 |
} |
| 575 |
|
| 576 |
$zip->close(); |
| 577 |
|
| 578 |
return $entries; |
| 579 |
} |
| 580 |
|
| 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; |
| 588 |
} |
| 589 |
|
| 590 |
foreach ( $contents as $entry ) { |
| 591 |
$entries[] = $entry['filename']; |
| 592 |
} |
| 593 |
|
| 594 |
return $entries; |
| 595 |
} |
| 596 |
|
| 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 ) { |
| 607 |
|
| 608 |
$disallowed = array(); |
| 609 |
|
| 610 |
foreach ( $entries as $entry ) { |
| 611 |
|
| 612 |
// Directories carry no payload of their own. |
| 613 |
if ( '/' === substr( $entry, -1 ) ) { |
| 614 |
continue; |
| 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 |
} |
| 648 |
} |
| 649 |
|
| 650 |
return $disallowed; |
| 651 |
} |
| 652 |
|
| 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() { |
| 664 |
|
| 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 |
); |
| 670 |
} |
| 671 |
|
| 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 |
); |
| 679 |
} |
| 680 |
|
| 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' ) ); |
| 684 |
|
| 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 |
); |
| 690 |
} |
| 691 |
|
| 692 |
// Reading the archive proves the contents are a zip, not just the name. |
| 693 |
$entries = $this->get_archive_file_list( $tmp_name ); |
| 694 |
|
| 695 |
if ( is_wp_error( $entries ) ) { |
| 696 |
return $entries; |
| 697 |
} |
| 698 |
|
| 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 ) ) { |
| 744 |
return true; |
| 745 |
} |
| 746 |
} |
| 747 |
|
| 748 |
return false; |
| 749 |
} |
| 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 |
*/ |
| 760 |
public function rmp_upload_theme() { |
| 761 |
|
| 762 |
// Check nonce to verify the authenticate upload file. |
| 763 |
check_ajax_referer( 'rmp_nonce', 'rmp_theme_upload_nonce' ); |
| 764 |
|
| 765 |
status_header( 200 ); |
| 766 |
|
| 767 |
$uploaded = $this->process_theme_upload(); |
| 768 |
|
| 769 |
if ( is_wp_error( $uploaded ) ) { |
| 770 |
wp_send_json_error( |
| 771 |
array( 'message' => $uploaded->get_error_message() ) |
| 772 |
); |
| 773 |
} |
| 774 |
|
| 775 |
wp_send_json_success( |
| 776 |
array( 'message' => esc_html__( 'Theme Imported Successfully.', 'responsive-menu' ) ) |
| 777 |
); |
| 778 |
} |
| 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() { |
| 789 |
|
| 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 ); |
| 795 |
|
| 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'; |
| 807 |
|
| 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 |
} |
| 812 |
|
| 813 |
if ( file_exists( $config_file ) ) { |
| 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; |
| 819 |
} |
| 820 |
} |
| 821 |
|
| 822 |
return $themes; |
| 823 |
} |
| 824 |
|
| 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(); |
| 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() { |
| 859 |
check_ajax_referer( 'rmp_nonce', 'ajax_nonce' ); |
| 860 |
|
| 861 |
$theme_name = isset( $_POST['theme_name'] ) ? sanitize_text_field( wp_unslash( $_POST['theme_name'] ) ) : ''; |
| 862 |
if ( empty( $theme_name ) ) { |
| 863 |
wp_send_json_error( array( 'message' => esc_html__( 'Theme Name Missing', 'responsive-menu' ) ) ); |
| 864 |
} |
| 865 |
|
| 866 |
$menu_id = isset( $_POST['menu_id'] ) ? sanitize_text_field( wp_unslash( $_POST['menu_id'] ) ) : ''; |
| 867 |
if ( empty( $menu_id ) ) { |
| 868 |
wp_send_json_error( |
| 869 |
array( 'message' => esc_html__( 'Menu ID missing !', 'responsive-menu' ) ) |
| 870 |
); |
| 871 |
} |
| 872 |
|
| 873 |
if ( ! current_user_can( 'edit_post', $menu_id ) ) { |
| 874 |
wp_send_json_error( array( 'message' => __( 'You can not edit menu !', 'responsive-menu' ) ) ); |
| 875 |
} |
| 876 |
|
| 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']; |
| 881 |
|
| 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 |
*/ |
| 889 |
if ( empty( $rmp_themes ) || ! is_array( $rmp_themes ) ) { |
| 890 |
$rmp_themes = array(); |
| 891 |
} |
| 892 |
|
| 893 |
$rmp_themes[ $theme_name ] = $options; |
| 894 |
|
| 895 |
update_option( self::$theme_option, $rmp_themes ); |
| 896 |
|
| 897 |
$data = $this->saved_theme_list(); |
| 898 |
|
| 899 |
wp_send_json_success( |
| 900 |
array( |
| 901 |
'themes' => $data, |
| 902 |
'message' => $theme_name . ' is saved', |
| 903 |
) |
| 904 |
); |
| 905 |
|
| 906 |
exit(); |
| 907 |
} |
| 908 |
|
| 909 |
|
| 910 |
public function saved_theme_list() { |
| 911 |
$rmp_themes = get_option( self::$theme_option ); |
| 912 |
|
| 913 |
if ( empty( $rmp_themes ) ) { |
| 914 |
return; |
| 915 |
} |
| 916 |
|
| 917 |
$theme_list = array(); |
| 918 |
foreach ( $rmp_themes as $theme_name => $options ) { |
| 919 |
$theme_list[] = $theme_name; |
| 920 |
} |
| 921 |
|
| 922 |
return $theme_list; |
| 923 |
} |
| 924 |
|
| 925 |
public function get_saved_theme_options( $theme_name ) { |
| 926 |
$rmp_themes = get_option( self::$theme_option ); |
| 927 |
|
| 928 |
if ( empty( $rmp_themes ) ) { |
| 929 |
return; |
| 930 |
} |
| 931 |
|
| 932 |
foreach ( $rmp_themes as $theme_key => $options ) { |
| 933 |
if ( $theme_name === $theme_key ) { |
| 934 |
return $options; |
| 935 |
} |
| 936 |
} |
| 937 |
|
| 938 |
return array(); |
| 939 |
} |
| 940 |
|
| 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 ) { |
| 950 |
$rmp_themes = $this->saved_theme_list(); |
| 951 |
|
| 952 |
// Check the list is empty or not. |
| 953 |
if ( empty( $rmp_themes ) ) { |
| 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; |
| 960 |
} |
| 961 |
|
| 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 |
| 981 |
} |
| 982 |
} |
| 983 |
|
| 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(); |
| 993 |
|
| 994 |
if ( empty( $uploaded_themes ) || ! is_array( $uploaded_themes ) ) { |
| 995 |
$uploaded_themes = array(); |
| 996 |
} |
| 997 |
|
| 998 |
foreach ( $themes as $theme ) { |
| 999 |
|
| 1000 |
// Avoid the themes which are already uploaded. |
| 1001 |
if ( in_array( strtolower( $theme['slug'] ), $uploaded_themes, true ) ) { |
| 1002 |
continue; |
| 1003 |
} |
| 1004 |
|
| 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 |
); |
| 1021 |
} |
| 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"> |
| 1029 |
<div class="rmp-item-card_contents"> |
| 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> |
| 1067 |
</div> |
| 1068 |
</div> |
| 1069 |
</li> |
| 1070 |
<?php |
| 1071 |
} |
| 1072 |
|
| 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 |
} |
| 1081 |
} |
| 1082 |
|
| 1083 |
public function all_theme_combine_list() { |
| 1084 |
$all_themes = array(); |
| 1085 |
|
| 1086 |
// Local saved themes. |
| 1087 |
$themes = $this->saved_theme_list(); |
| 1088 |
|
| 1089 |
if ( ! empty( $themes ) && is_array( $themes ) ) { |
| 1090 |
foreach ( $themes as $theme ) { |
| 1091 |
$all_themes[] = array( |
| 1092 |
'name' => $theme, |
| 1093 |
'type' => 'Template', |
| 1094 |
); |
| 1095 |
} |
| 1096 |
} |
| 1097 |
|
| 1098 |
// Uploaded themes. |
| 1099 |
$themes = $this->get_themes_from_uploads(); |
| 1100 |
if ( ! empty( $themes ) && is_array( $themes ) ) { |
| 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 |
); |
| 1107 |
} |
| 1108 |
} |
| 1109 |
|
| 1110 |
return $all_themes; |
| 1111 |
} |
| 1112 |
|
| 1113 |
/** |
| 1114 |
* Returns the thumbnail of theme. |
| 1115 |
* |
| 1116 |
* @since 4.0.0 |
| 1117 |
* |
| 1118 |
* @return string|url|null |
| 1119 |
*/ |
| 1120 |
public function get_theme_preview_url( $theme_name ) { |
| 1121 |
|
| 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 ); |
| 1127 |
|
| 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 |
|
| 1144 |
if ( file_exists( $config_file ) ) { |
| 1145 |
$config = json_decode( $wp_filesystem->get_contents( $config_file ), true ); |
| 1146 |
if ( $config['name'] == $theme_name ) { |
| 1147 |
return $theme_preview_url; |
| 1148 |
} |
| 1149 |
} |
| 1150 |
} |
| 1151 |
|
| 1152 |
return; |
| 1153 |
} |
| 1154 |
|
| 1155 |
/** |
| 1156 |
* Function to return the theme thumbnail element. |
| 1157 |
* |
| 1158 |
* @since 4.0.0 |
| 1159 |
* |
| 1160 |
* @return strinh|HTML|null |
| 1161 |
*/ |
| 1162 |
public function get_theme_thumbnail( $theme_name, $theme_type ) { |
| 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' ) |
| 1414 |
); |
| 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 |
| 1489 |
); |
| 1490 |
} |
| 1491 |
|
| 1492 |
$html .= '</ul>'; |
| 1493 |
|
| 1494 |
return $html; |
| 1495 |
} |
| 1496 |
|
| 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() { |
| 1506 |
|
| 1507 |
// Check nonce to verify the authenticate upload file. |
| 1508 |
check_ajax_referer( 'rmp_nonce', 'ajax_nonce' ); |
| 1509 |
|
| 1510 |
// Upload the file in upload directory. |
| 1511 |
status_header( 200 ); |
| 1512 |
|
| 1513 |
$uploaded = $this->process_theme_upload(); |
| 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 |
} |
| 1569 |
|