assets
2 years ago
TemplateSourceContent.php
4 months ago
TemplatesLib.php
2 weeks ago
index.php
2 years ago
TemplatesLib.php
1083 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Template Library. |
| 4 | * |
| 5 | * @package ShopPress |
| 6 | */ |
| 7 | |
| 8 | namespace ShopPress\Elementor\TemplateLibrary; |
| 9 | |
| 10 | defined( 'ABSPATH' ) || exit; |
| 11 | |
| 12 | use Elementor\User; |
| 13 | use Elementor\Plugin; |
| 14 | use Elementor\TemplateLibrary\Source_Local; |
| 15 | use Elementor\Core\Common\Modules\Ajax\Module as Ajax; |
| 16 | use Elementor\Modules\KitElementsDefaults\Utils\Settings_Sanitizer; |
| 17 | use Elementor\Core\Utils\Collection; |
| 18 | |
| 19 | /** |
| 20 | * Template Library. |
| 21 | * |
| 22 | * @since 1.2.0 |
| 23 | */ |
| 24 | class TemplatesLib |
| 25 | { |
| 26 | |
| 27 | /** |
| 28 | * library option key. |
| 29 | */ |
| 30 | const LIBRARY_OPTION_KEY = 'shoppress_templates_library'; |
| 31 | |
| 32 | /** |
| 33 | * Presets option key. |
| 34 | */ |
| 35 | const PRESETS_OPTION_KEY = 'shoppress_presets_library'; |
| 36 | |
| 37 | /** |
| 38 | * Presets option key. |
| 39 | */ |
| 40 | const PRESETS_ELEMENTS_OPTION_KEY = 'shoppress_preset_elements'; |
| 41 | |
| 42 | /** |
| 43 | * API templates URL. |
| 44 | * |
| 45 | * Holds the URL of the templates API. |
| 46 | * |
| 47 | * @access public |
| 48 | * @static |
| 49 | * |
| 50 | * @var string API URL. |
| 51 | */ |
| 52 | public static $api_url = 'https://katademos.com/api/shoppress-template-manager/v1/'; |
| 53 | |
| 54 | /** |
| 55 | * templates Path. |
| 56 | * |
| 57 | * Holds the URL of the templates path. |
| 58 | * |
| 59 | * @access public |
| 60 | * @static |
| 61 | * |
| 62 | * @var string path. |
| 63 | */ |
| 64 | public static $path; |
| 65 | |
| 66 | /** |
| 67 | * templates url. |
| 68 | * |
| 69 | * Holds the URL of the templates url. |
| 70 | * |
| 71 | * @access public |
| 72 | * @static |
| 73 | * |
| 74 | * @var string url. |
| 75 | */ |
| 76 | public static $url; |
| 77 | |
| 78 | /** |
| 79 | * Init. |
| 80 | * |
| 81 | * Initializes the hooks. |
| 82 | * |
| 83 | * @since 1.2.0 |
| 84 | * @access public |
| 85 | * |
| 86 | * @return void |
| 87 | */ |
| 88 | public static function init() |
| 89 | { |
| 90 | self::$path = plugin_dir_path(__FILE__); |
| 91 | self::$url = plugin_dir_url(__FILE__); |
| 92 | |
| 93 | include_once self::$path . 'TemplateSourceContent.php'; |
| 94 | |
| 95 | add_action('elementor/init', array(__CLASS__, 'register_source')); |
| 96 | add_action('elementor/editor/after_enqueue_scripts', array(__CLASS__, 'enqueue_editor_scripts')); |
| 97 | add_action('elementor/ajax/register_actions', array(__CLASS__, 'register_ajax_actions')); |
| 98 | add_action('elementor/editor/footer', array(__CLASS__, 'render_template')); |
| 99 | add_action('elementor/editor/after_enqueue_styles', array(__CLASS__, 'editor_enqueue_styles'), 0); |
| 100 | add_action('elementor/preview/enqueue_styles', array(__CLASS__, 'preview_enqueue_styles')); |
| 101 | add_action('wp_ajax_shoppress_get_preset_element', array(__CLASS__, 'shoppress_get_preset_element')); |
| 102 | add_action('wp_ajax_nopriv_shoppress_get_preset_element', array(__CLASS__, 'shoppress_get_preset_element')); |
| 103 | } |
| 104 | |
| 105 | /** |
| 106 | * Register source. |
| 107 | * |
| 108 | * Registers the library source. |
| 109 | * |
| 110 | * @since 1.2.0 |
| 111 | * @access public |
| 112 | * |
| 113 | * @return void |
| 114 | */ |
| 115 | public static function register_source() |
| 116 | { |
| 117 | Plugin::$instance->templates_manager->register_source('\ShopPress\Elementor\TemplateLibrary\TemplateSourceContent'); |
| 118 | } |
| 119 | |
| 120 | /** |
| 121 | * Enqueue Editor Style. |
| 122 | * |
| 123 | * Enqueues required scripts in Elementor edit mode. |
| 124 | * |
| 125 | * @since 1.2.0 |
| 126 | * @access public |
| 127 | * |
| 128 | * @return void |
| 129 | */ |
| 130 | public static function editor_enqueue_styles() |
| 131 | { |
| 132 | wp_enqueue_style('shoppress-elementor-template-manager-editor', self::$url . 'assets/css/template-manager-editor.css', array(), SHOPPRESS_VERSION); |
| 133 | wp_enqueue_style('shoppress-elementor-template-manager-editor-dark', self::$url . 'assets/css/template-manager-editor-dark.css', array(), SHOPPRESS_VERSION); |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Enqueue Editor Style. |
| 138 | * |
| 139 | * Enqueues required scripts in Elementor edit mode. |
| 140 | * |
| 141 | * @since 1.2.0 |
| 142 | * @access public |
| 143 | * |
| 144 | * @return void |
| 145 | */ |
| 146 | public static function preview_enqueue_styles() |
| 147 | { |
| 148 | wp_enqueue_style('shoppress-elementor-template-manager-preview', self::$url . 'assets/css/template-manager-preview.css', array(), SHOPPRESS_VERSION); |
| 149 | } |
| 150 | |
| 151 | /** |
| 152 | * Enqueue Editor Scripts. |
| 153 | * |
| 154 | * Enqueues required scripts in Elementor edit mode. |
| 155 | * |
| 156 | * @since 1.2.0 |
| 157 | * @access public |
| 158 | * |
| 159 | * @return void |
| 160 | */ |
| 161 | public static function enqueue_editor_scripts() |
| 162 | { |
| 163 | |
| 164 | $post_types = array( |
| 165 | 'shoppress_pages', |
| 166 | 'shoppress_loop', |
| 167 | 'shoppress_myaccount', |
| 168 | ); |
| 169 | |
| 170 | // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Editor context, post ID for asset loading, sanitized with absint(). |
| 171 | $post_type = get_post_type( isset( $_GET['post'] ) ? absint( wp_unslash( $_GET['post'] ) ) : 0 ); |
| 172 | |
| 173 | if (! in_array($post_type, $post_types)) { |
| 174 | return; |
| 175 | } |
| 176 | |
| 177 | wp_enqueue_script('sp-nicescroll-script'); |
| 178 | wp_enqueue_script( |
| 179 | 'shoppress-templates-lib', |
| 180 | self::$url . 'assets/js/templates-lib.js', |
| 181 | array( |
| 182 | 'jquery', |
| 183 | 'sp-nicescroll-script', |
| 184 | 'backbone-marionette', |
| 185 | 'backbone-radio', |
| 186 | 'elementor-common-modules', |
| 187 | 'elementor-dialog', |
| 188 | ), |
| 189 | SHOPPRESS_VERSION, |
| 190 | true |
| 191 | ); |
| 192 | |
| 193 | $post_type = get_post_type(); |
| 194 | $post_id = get_the_ID(); |
| 195 | $template_groups = array(); |
| 196 | $post_types = array( |
| 197 | 'shoppress_pages', |
| 198 | ); |
| 199 | if (in_array($post_type, $post_types)) { |
| 200 | |
| 201 | $types = (array) get_post_meta($post_id, 'custom_type', true); |
| 202 | |
| 203 | if (in_array('archive', $types) || in_array('shop', $types)) { |
| 204 | |
| 205 | $template_groups['templates/shop'] = array( |
| 206 | 'title' => __('Shop', 'shop-press'), |
| 207 | 'filter' => array( |
| 208 | 'source' => 'shop', |
| 209 | 'type' => 'shop', |
| 210 | 'subtype' => 'shop', |
| 211 | ), |
| 212 | ); |
| 213 | } elseif (in_array('single', $types)) { |
| 214 | |
| 215 | $template_groups['templates/single_product'] = array( |
| 216 | 'title' => __('Product Single', 'shop-press'), |
| 217 | 'filter' => array( |
| 218 | 'source' => 'single_product', |
| 219 | 'type' => 'single_product', |
| 220 | 'subtype' => 'single_product', |
| 221 | ), |
| 222 | ); |
| 223 | } elseif (in_array('cart', $types)) { |
| 224 | $template_groups['templates/cart'] = array( |
| 225 | 'title' => __('Cart', 'shop-press'), |
| 226 | 'filter' => array( |
| 227 | 'source' => 'cart', |
| 228 | 'type' => 'cart', |
| 229 | 'subtype' => 'cart', |
| 230 | ), |
| 231 | ); |
| 232 | } elseif (in_array('empty_cart', $types)) { |
| 233 | $template_groups['templates/empty_cart'] = array( |
| 234 | 'title' => __('Empty Cart', 'shop-press'), |
| 235 | 'filter' => array( |
| 236 | 'source' => 'empty_cart', |
| 237 | 'type' => 'empty_cart', |
| 238 | 'subtype' => 'empty_cart', |
| 239 | ), |
| 240 | ); |
| 241 | } elseif (in_array('checkout', $types)) { |
| 242 | |
| 243 | $template_groups['templates/checkout'] = array( |
| 244 | 'title' => __('Checkout', 'shop-press'), |
| 245 | 'filter' => array( |
| 246 | 'source' => 'checkout', |
| 247 | 'type' => 'checkout', |
| 248 | 'subtype' => 'checkout', |
| 249 | ), |
| 250 | ); |
| 251 | } elseif (in_array('checkout', $types)) { |
| 252 | |
| 253 | $template_groups['templates/checkout'] = array( |
| 254 | 'title' => __('Checkout', 'shop-press'), |
| 255 | 'filter' => array( |
| 256 | 'source' => 'checkout', |
| 257 | 'type' => 'checkout', |
| 258 | 'subtype' => 'checkout', |
| 259 | ), |
| 260 | ); |
| 261 | } elseif (in_array('thank_you', $types)) { |
| 262 | |
| 263 | $template_groups['templates/thank_you'] = array( |
| 264 | 'title' => __('Thank You', 'shop-press'), |
| 265 | 'filter' => array( |
| 266 | 'source' => 'thank_you', |
| 267 | 'type' => 'thank_you', |
| 268 | 'subtype' => 'thank_you', |
| 269 | ), |
| 270 | ); |
| 271 | } elseif (in_array('compare', $types)) { |
| 272 | |
| 273 | $template_groups['templates/compare'] = array( |
| 274 | 'title' => __('Compare', 'shop-press'), |
| 275 | 'filter' => array( |
| 276 | 'source' => 'compare', |
| 277 | 'type' => 'compare', |
| 278 | 'subtype' => 'compare', |
| 279 | ), |
| 280 | ); |
| 281 | } elseif (in_array('quick_view', $types)) { |
| 282 | |
| 283 | $template_groups['templates/quick_view'] = array( |
| 284 | 'title' => __('Quick View', 'shop-press'), |
| 285 | 'filter' => array( |
| 286 | 'source' => 'quick_view', |
| 287 | 'type' => 'quick_view', |
| 288 | 'subtype' => 'quick_view', |
| 289 | ), |
| 290 | ); |
| 291 | } elseif (in_array('wishlist', $types)) { |
| 292 | |
| 293 | $template_groups['templates/wishlist'] = array( |
| 294 | 'title' => __('Wishlist', 'shop-press'), |
| 295 | 'filter' => array( |
| 296 | 'source' => 'wishlist', |
| 297 | 'type' => 'wishlist', |
| 298 | 'subtype' => 'wishlist', |
| 299 | ), |
| 300 | ); |
| 301 | } elseif (in_array('wishlist', $types)) { |
| 302 | |
| 303 | $template_groups['templates/wishlist'] = array( |
| 304 | 'title' => __('Wishlist', 'shop-press'), |
| 305 | 'filter' => array( |
| 306 | 'source' => 'wishlist', |
| 307 | 'type' => 'wishlist', |
| 308 | 'subtype' => 'wishlist', |
| 309 | ), |
| 310 | ); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | if ('shoppress_loop' === $post_type) { |
| 315 | |
| 316 | $template_groups['templates/product_loop'] = array( |
| 317 | 'title' => __('Product Loop', 'shop-press'), |
| 318 | 'filter' => array( |
| 319 | 'source' => 'product_loop', |
| 320 | 'type' => 'product_loop', |
| 321 | 'subtype' => 'product_loop', |
| 322 | ), |
| 323 | ); |
| 324 | } |
| 325 | |
| 326 | if ('shoppress_myaccount' === $post_type) { |
| 327 | |
| 328 | $template_groups['templates/my_account'] = array( |
| 329 | 'title' => __('My Account', 'shop-press'), |
| 330 | 'filter' => array( |
| 331 | 'source' => 'my_account', |
| 332 | 'type' => 'my_account', |
| 333 | 'subtype' => 'my_account', |
| 334 | ), |
| 335 | ); |
| 336 | } |
| 337 | |
| 338 | $elementor_data = get_post_meta($post_id, '_elementor_data', true); |
| 339 | $open_templates_lib = (empty($elementor_data) || '[]' === $elementor_data) ? 'yes' : 'no'; |
| 340 | $is_kata = false; |
| 341 | $theme = wp_get_theme(); |
| 342 | $parent_theme = $theme->parent(); |
| 343 | if (false !== strpos($theme->get('TextDomain'), 'kata') || ($parent_theme && false !== strpos($parent_theme->get('TextDomain'), 'kata'))) { |
| 344 | $is_kata = true; |
| 345 | } |
| 346 | |
| 347 | wp_localize_script( |
| 348 | 'shoppress-templates-lib', |
| 349 | 'shoppress_templates_lib', |
| 350 | array( |
| 351 | 'template_groups' => $template_groups, |
| 352 | 'open_templates_lib' => $open_templates_lib, |
| 353 | 'is_kata' => $is_kata, |
| 354 | ) |
| 355 | ); |
| 356 | } |
| 357 | |
| 358 | /** |
| 359 | * Init ajax calls. |
| 360 | * |
| 361 | * Initialize template library ajax calls for allowed ajax requests. |
| 362 | * |
| 363 | * @since 1.2.0 |
| 364 | * @access public |
| 365 | * |
| 366 | * @param Ajax $ajax Elementor's Ajax object. |
| 367 | * @return void |
| 368 | */ |
| 369 | public static function register_ajax_actions(Ajax $ajax) |
| 370 | { |
| 371 | $library_ajax_requests = array( |
| 372 | 'shoppress_get_library_data', |
| 373 | 'shoppress_get_template_data', |
| 374 | ); |
| 375 | |
| 376 | foreach ($library_ajax_requests as $ajax_request) { |
| 377 | $ajax->register_ajax_action( |
| 378 | $ajax_request, |
| 379 | function ($data) use ($ajax_request) { |
| 380 | return self::handle_ajax_request($ajax_request, $data); |
| 381 | } |
| 382 | ); |
| 383 | } |
| 384 | } |
| 385 | |
| 386 | /** |
| 387 | * Handle ajax request. |
| 388 | * |
| 389 | * Fire authenticated ajax actions for any given ajax request. |
| 390 | * |
| 391 | * @since 1.2.0 |
| 392 | * @access private |
| 393 | * |
| 394 | * @param string $ajax_request Ajax request. |
| 395 | * @param array $data Elementor data. |
| 396 | * |
| 397 | * @return mixed |
| 398 | * @throws \Exception Throws error message. |
| 399 | */ |
| 400 | private static function handle_ajax_request($ajax_request, array $data) |
| 401 | { |
| 402 | if (! User::is_current_user_can_edit_post_type(Source_Local::CPT)) { |
| 403 | throw new \Exception('Access Denied'); |
| 404 | } |
| 405 | |
| 406 | if (! empty($data['editor_post_id'])) { |
| 407 | $editor_post_id = absint($data['editor_post_id']); |
| 408 | |
| 409 | if (! get_post($editor_post_id)) { |
| 410 | // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message is not directly output. |
| 411 | throw new \Exception(__('Post not found.', 'shop-press')); |
| 412 | } |
| 413 | |
| 414 | Plugin::$instance->db->switch_to_post($editor_post_id); |
| 415 | } |
| 416 | |
| 417 | $result = call_user_func(array(__CLASS__, $ajax_request), $data); |
| 418 | |
| 419 | if (is_wp_error($result)) { |
| 420 | // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message is not directly output. |
| 421 | throw new \Exception($result->get_error_message()); |
| 422 | } |
| 423 | |
| 424 | return $result; |
| 425 | } |
| 426 | |
| 427 | /** |
| 428 | * Get library data. |
| 429 | * |
| 430 | * Get data for template library. |
| 431 | * |
| 432 | * @since 1.2.0 |
| 433 | * @access public |
| 434 | * |
| 435 | * @param array $args Arguments. |
| 436 | * |
| 437 | * @return array Collection of templates data. |
| 438 | */ |
| 439 | public static function shoppress_get_library_data(array $args) |
| 440 | { |
| 441 | $library_data = self::get_library_data(! empty($args['sync'])); |
| 442 | |
| 443 | // Ensure all document are registered. |
| 444 | Plugin::$instance->documents->get_document_types(); |
| 445 | |
| 446 | return array( |
| 447 | 'templates' => self::get_templates(), |
| 448 | 'config' => $library_data, |
| 449 | ); |
| 450 | } |
| 451 | |
| 452 | /** |
| 453 | * Get templates. |
| 454 | * |
| 455 | * Retrieve all the templates from all the registered sources. |
| 456 | * |
| 457 | * @since 1.2.0 |
| 458 | * @access public |
| 459 | * |
| 460 | * @return array Templates array. |
| 461 | */ |
| 462 | public static function get_templates() |
| 463 | { |
| 464 | $source = Plugin::$instance->templates_manager->get_source('product_loop'); |
| 465 | |
| 466 | return $source->get_items(); |
| 467 | } |
| 468 | |
| 469 | /** |
| 470 | * Get templates data. |
| 471 | * |
| 472 | * This function the templates data. |
| 473 | * |
| 474 | * @since 1.2.0 |
| 475 | * @access private |
| 476 | * @static |
| 477 | * |
| 478 | * @param bool $force_update Optional. Whether to force the data retrieval or |
| 479 | * not. Default is false. |
| 480 | * |
| 481 | * @return array|false Templates data, or false. |
| 482 | */ |
| 483 | private static function get_templates_data($force_update = false) |
| 484 | { |
| 485 | $cache_key = 'shoppress_templates_data_' . SHOPPRESS_VERSION; |
| 486 | |
| 487 | $templates_data = get_transient($cache_key); |
| 488 | |
| 489 | if ($force_update || false === $templates_data) { |
| 490 | $timeout = ($force_update) ? 25 : 8; |
| 491 | |
| 492 | $response = wp_remote_get( |
| 493 | self::$api_url . 'templates.json', |
| 494 | array( |
| 495 | 'timeout' => $timeout, |
| 496 | ) |
| 497 | ); |
| 498 | |
| 499 | if (is_wp_error($response) || 200 !== (int) wp_remote_retrieve_response_code($response)) { |
| 500 | set_transient($cache_key, array(), 2 * HOUR_IN_SECONDS); |
| 501 | |
| 502 | return false; |
| 503 | } |
| 504 | |
| 505 | $templates_data = json_decode(wp_remote_retrieve_body($response), true); |
| 506 | |
| 507 | if (empty($templates_data) || ! is_array($templates_data)) { |
| 508 | set_transient($cache_key, array(), 2 * HOUR_IN_SECONDS); |
| 509 | |
| 510 | return false; |
| 511 | } |
| 512 | |
| 513 | if (isset($templates_data)) { |
| 514 | update_option(self::LIBRARY_OPTION_KEY, $templates_data, 'no'); |
| 515 | } |
| 516 | |
| 517 | set_transient($cache_key, $templates_data, 12 * HOUR_IN_SECONDS); |
| 518 | } |
| 519 | |
| 520 | return $templates_data; |
| 521 | } |
| 522 | |
| 523 | /** |
| 524 | * Get Presets data. |
| 525 | * |
| 526 | * This function the Presets data. |
| 527 | * |
| 528 | * @since 1.2.0 |
| 529 | * @access public |
| 530 | * @static |
| 531 | * |
| 532 | * @param bool $force_update Optional. Whether to force the data retrieval or |
| 533 | * not. Default is false. |
| 534 | * |
| 535 | * @return array|false Templates data, or false. |
| 536 | */ |
| 537 | public static function get_presets($force_update = false) |
| 538 | { |
| 539 | $cache_key = 'shoppress_presets_data_' . SHOPPRESS_VERSION; |
| 540 | |
| 541 | $presets_data = get_transient($cache_key); |
| 542 | |
| 543 | if ($force_update || false === $presets_data) { |
| 544 | $timeout = ($force_update) ? 25 : 8; |
| 545 | |
| 546 | $response = wp_remote_get( |
| 547 | self::$api_url . 'presets/presets.json', |
| 548 | array( |
| 549 | 'timeout' => $timeout, |
| 550 | ) |
| 551 | ); |
| 552 | |
| 553 | if (is_wp_error($response) || 200 !== (int) wp_remote_retrieve_response_code($response)) { |
| 554 | set_transient($cache_key, array(), 2 * HOUR_IN_SECONDS); |
| 555 | |
| 556 | return false; |
| 557 | } |
| 558 | |
| 559 | $presets_data = json_decode(wp_remote_retrieve_body($response), true); |
| 560 | |
| 561 | if (empty($presets_data) || ! is_array($presets_data)) { |
| 562 | set_transient($cache_key, array(), 2 * HOUR_IN_SECONDS); |
| 563 | |
| 564 | return false; |
| 565 | } |
| 566 | |
| 567 | if (isset($presets_data)) { |
| 568 | update_option(self::PRESETS_OPTION_KEY, $presets_data, 'no'); |
| 569 | } |
| 570 | |
| 571 | set_transient($cache_key, $presets_data, 12 * HOUR_IN_SECONDS); |
| 572 | } |
| 573 | |
| 574 | return $presets_data; |
| 575 | } |
| 576 | |
| 577 | /** |
| 578 | * Get Preset element data. |
| 579 | * |
| 580 | * This function the Preset element data. |
| 581 | * |
| 582 | * @since 1.2.0 |
| 583 | * @access public |
| 584 | * @static |
| 585 | * |
| 586 | * @return array|false Templates data, or false. |
| 587 | */ |
| 588 | public static function shoppress_get_preset_element() |
| 589 | { |
| 590 | |
| 591 | if (! check_ajax_referer('shoppress_get_preset_element', 'nonce')) { |
| 592 | wp_send_json('Invalid nonce!', 400); |
| 593 | wp_die(); |
| 594 | } |
| 595 | |
| 596 | $element = isset( $_POST['element'] ) ? sanitize_text_field( wp_unslash( $_POST['element'] ) ) : ''; |
| 597 | $reset = isset( $_POST['reset'] ) ? sanitize_text_field( wp_unslash( $_POST['reset'] ) ) : ''; |
| 598 | |
| 599 | $presets = get_option(self::PRESETS_ELEMENTS_OPTION_KEY); |
| 600 | |
| 601 | if (! isset($presets[$element]) || $reset === 'true') { |
| 602 | |
| 603 | $response = wp_remote_get( |
| 604 | self::$api_url . 'presets/elements/' . $element . '.json', |
| 605 | array('timeout' => 30) |
| 606 | ); |
| 607 | |
| 608 | if (is_wp_error($response) || 200 !== (int) wp_remote_retrieve_response_code($response)) { |
| 609 | wp_send_json('Unexpected Error, Code: ', wp_remote_retrieve_response_code($response)); |
| 610 | wp_die(); |
| 611 | } |
| 612 | |
| 613 | $presets_data = json_decode(wp_remote_retrieve_body($response), true); |
| 614 | |
| 615 | if (isset($presets_data)) { |
| 616 | $presets[$element] = $presets_data; |
| 617 | update_option(self::PRESETS_ELEMENTS_OPTION_KEY, $presets, 'no'); |
| 618 | } |
| 619 | |
| 620 | $presets = get_option(self::PRESETS_ELEMENTS_OPTION_KEY); |
| 621 | wp_send_json($presets, 200); |
| 622 | } else { |
| 623 | $presets = get_option(self::PRESETS_ELEMENTS_OPTION_KEY); |
| 624 | wp_send_json($presets, 200); |
| 625 | } |
| 626 | |
| 627 | wp_die(); |
| 628 | } |
| 629 | |
| 630 | /** |
| 631 | * Get templates data. |
| 632 | * |
| 633 | * Retrieve the templates data from a remote server. |
| 634 | * |
| 635 | * @since 1.2.0 |
| 636 | * @access public |
| 637 | * @static |
| 638 | * |
| 639 | * @param bool $force_update Optional. Whether to force the data update or |
| 640 | * not. Default is false. |
| 641 | * |
| 642 | * @return array The templates data. |
| 643 | */ |
| 644 | public static function get_library_data($force_update = false) |
| 645 | { |
| 646 | self::get_templates_data($force_update); |
| 647 | |
| 648 | $library_data = get_option(self::LIBRARY_OPTION_KEY); |
| 649 | |
| 650 | if (empty($library_data)) { |
| 651 | return array(); |
| 652 | } |
| 653 | |
| 654 | return $library_data; |
| 655 | } |
| 656 | |
| 657 | /** |
| 658 | * Test the upload of an image from a given URL. |
| 659 | * |
| 660 | * @since 1.3.8 |
| 661 | * |
| 662 | * @param string $image_url The URL of the image to test. |
| 663 | * @return bool Returns true if the image is valid and can be uploaded, false otherwise. |
| 664 | */ |
| 665 | public static function test_image_for_upload($image_url) |
| 666 | { |
| 667 | |
| 668 | // Check for if user can download images |
| 669 | if ( |
| 670 | (strpos('katademos.com', $image_url) !== false || strpos('webnus.net', $image_url) !== false) && |
| 671 | ! current_user_can('upload_files') |
| 672 | ) { |
| 673 | return false; |
| 674 | } |
| 675 | |
| 676 | // Check the URL of the image |
| 677 | if (! filter_var($image_url, FILTER_VALIDATE_URL)) { |
| 678 | return false; |
| 679 | } |
| 680 | |
| 681 | // Check the file type of the image |
| 682 | $file_type = wp_check_filetype($image_url); |
| 683 | if (false === $file_type['type'] && false === $file_type['ext']) { |
| 684 | return false; |
| 685 | } |
| 686 | |
| 687 | // Check the file extension of the image |
| 688 | $file_extension = pathinfo($image_url, PATHINFO_EXTENSION); |
| 689 | if (! in_array($file_extension, array('jpg', 'jpeg', 'png', 'gif'))) { |
| 690 | return false; |
| 691 | } |
| 692 | |
| 693 | // Check the upload directory |
| 694 | $upload_dir = wp_upload_dir(); |
| 695 | if (! is_dir($upload_dir['path'])) { |
| 696 | return false; |
| 697 | } |
| 698 | |
| 699 | return true; |
| 700 | } |
| 701 | |
| 702 | /** |
| 703 | * Downloads an image from a given URL and uploads it to the WordPress media library. |
| 704 | * |
| 705 | * @since 1.2.0 |
| 706 | * |
| 707 | * @param string $image_url The URL of the image to download and upload. |
| 708 | * |
| 709 | * @return int|false|string The attachment ID of the uploaded image, false if there was an error saving the image, or a string describing the error. |
| 710 | */ |
| 711 | public static function download_and_upload_image($image_url) |
| 712 | { |
| 713 | // Make sure WordPress core is loaded |
| 714 | if (! defined('ABSPATH')) { |
| 715 | require_once '../../../../wp-load.php'; // Adjust the path to wp-load.php if necessary |
| 716 | } |
| 717 | |
| 718 | // Test the upload of an image from a given URL. |
| 719 | static::test_image_for_upload($image_url); |
| 720 | |
| 721 | // Get the file extension from the image URL |
| 722 | $file_extension = pathinfo($image_url, PATHINFO_EXTENSION); |
| 723 | |
| 724 | // Generate a unique file name for the downloaded image |
| 725 | $unique_file_name = wp_unique_filename(wp_upload_dir()['path'], 'downloaded-image-' . time()) . '.' . $file_extension; |
| 726 | |
| 727 | // Download the image |
| 728 | $downloaded_image = download_url($image_url); |
| 729 | |
| 730 | if (! is_wp_error($downloaded_image)) { |
| 731 | // Save the downloaded image to the uploads directory |
| 732 | $upload_dir = wp_upload_dir(); |
| 733 | $target_path = $upload_dir['path'] . '/' . $unique_file_name; |
| 734 | |
| 735 | if (copy(strval($downloaded_image), $target_path)) { |
| 736 | |
| 737 | wp_delete_file($downloaded_image); |
| 738 | |
| 739 | // Insert the downloaded image as a media attachment |
| 740 | $attachment = array( |
| 741 | 'post_mime_type' => 'image/' . $file_extension, |
| 742 | 'post_title' => sanitize_file_name(pathinfo($unique_file_name, PATHINFO_FILENAME)), |
| 743 | 'post_content' => '', |
| 744 | 'post_status' => 'inherit', |
| 745 | ); |
| 746 | |
| 747 | $attachment_id = wp_insert_attachment($attachment, $target_path); |
| 748 | |
| 749 | if (! is_wp_error($attachment_id)) { |
| 750 | require_once ABSPATH . 'wp-admin/includes/image.php'; |
| 751 | $attachment_data = wp_generate_attachment_metadata($attachment_id, $target_path); |
| 752 | wp_update_attachment_metadata($attachment_id, $attachment_data); |
| 753 | |
| 754 | return array( |
| 755 | 'url' => wp_get_attachment_url($attachment_id), |
| 756 | 'id' => $attachment_id, |
| 757 | ); |
| 758 | } else { |
| 759 | return false; |
| 760 | } |
| 761 | } else { |
| 762 | return false; |
| 763 | } |
| 764 | } else { |
| 765 | return false; |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | /** |
| 770 | * Updates the images in the input array. |
| 771 | * |
| 772 | * @since 1.2.0 |
| 773 | * |
| 774 | * @param array $inputArray The input array containing the content and elements. |
| 775 | * |
| 776 | * @return array The updated input array with the images updated. |
| 777 | */ |
| 778 | public static function update_images($data) |
| 779 | { |
| 780 | |
| 781 | foreach ($data['content'] as $section_key => $section) { |
| 782 | foreach ($section['elements'] as $elements_key => $elements) { |
| 783 | foreach ($elements as $element_key => $element) { |
| 784 | // if it's element/widget |
| 785 | if ($element_key === 'elements') { |
| 786 | foreach ($element as $widgets_key => $widgets) { |
| 787 | foreach ($widgets as $widget_id => $widget) { |
| 788 | if (is_array($widget)) { |
| 789 | foreach ($widget as $widget_setting_key => $widget_setting) { |
| 790 | if (is_array($widget_setting) && ! empty($widget_setting)) { |
| 791 | |
| 792 | // update images for repeater |
| 793 | if (isset($widget_setting[0])) { |
| 794 | foreach ($widget_setting as $repeater_key => $repeater_value) { |
| 795 | if (is_array($repeater_value)) { |
| 796 | foreach ($repeater_value as $repeater_item_key => $repeater_item_value) { |
| 797 | if (is_array($repeater_item_value) && isset($repeater_item_value['url']) && isset($repeater_item_value['id'])) { |
| 798 | $new_image = static::download_and_upload_image(static::update_template_url($repeater_item_value['url'])); |
| 799 | $data['content'][$section_key]['elements'][$elements_key][$element_key][$widgets_key][$widget_id][$widget_setting_key][$repeater_key][$repeater_item_key]['url'] = $new_image['url']; |
| 800 | $data['content'][$section_key]['elements'][$elements_key][$element_key][$widgets_key][$widget_id][$widget_setting_key][$repeater_key][$repeater_item_key]['id'] = $new_image['id']; |
| 801 | } |
| 802 | } |
| 803 | } |
| 804 | } |
| 805 | } |
| 806 | |
| 807 | // update images |
| 808 | if (is_array($widget_setting) && isset($widget_setting['url']) && isset($widget_setting['id'])) { |
| 809 | $new_image = static::download_and_upload_image(static::update_template_url($widget_setting['url'])); |
| 810 | $data['content'][$section_key]['elements'][$elements_key][$element_key][$widgets_key][$widget_id][$widget_setting_key]['url'] = $new_image['url']; |
| 811 | $data['content'][$section_key]['elements'][$elements_key][$element_key][$widgets_key][$widget_id][$widget_setting_key]['id'] = $new_image['id']; |
| 812 | } |
| 813 | } |
| 814 | } |
| 815 | } |
| 816 | } |
| 817 | } |
| 818 | } |
| 819 | } |
| 820 | } |
| 821 | } |
| 822 | |
| 823 | return $data; |
| 824 | } |
| 825 | |
| 826 | /** |
| 827 | * Sanitize Elements |
| 828 | * |
| 829 | * @param array $template_data |
| 830 | * @param array|null $types |
| 831 | * |
| 832 | * @since 1.2.0 |
| 833 | * |
| 834 | * @return array |
| 835 | */ |
| 836 | public static function sanitize_elements($template_data, $types = null) |
| 837 | { |
| 838 | |
| 839 | if (! is_array($template_data)) { |
| 840 | |
| 841 | return $template_data; |
| 842 | } |
| 843 | |
| 844 | if (is_null($types)) { |
| 845 | |
| 846 | $element_types = array_keys(Plugin::$instance->elements_manager->get_element_types()); |
| 847 | $widget_types = array_keys(Plugin::$instance->widgets_manager->get_widget_types()); |
| 848 | |
| 849 | $types = array_merge($element_types, $widget_types); |
| 850 | } |
| 851 | |
| 852 | foreach ($template_data as $k => $data) { |
| 853 | |
| 854 | $elements = $data['elements'] ?? array(); |
| 855 | if (! empty($elements)) { |
| 856 | |
| 857 | $template_data[$k]['elements'] = array_values( |
| 858 | static::sanitize_elements($elements, $types) |
| 859 | ); |
| 860 | } else { |
| 861 | |
| 862 | $widget_type = $data['widgetType'] ?? false; |
| 863 | if ($widget_type && ! in_array($widget_type, $types)) { |
| 864 | unset($template_data[$k]); |
| 865 | } |
| 866 | } |
| 867 | } |
| 868 | |
| 869 | return $template_data; |
| 870 | } |
| 871 | |
| 872 | /** |
| 873 | * Get template content. |
| 874 | * |
| 875 | * Retrieve the templates content received from a remote server. |
| 876 | * |
| 877 | * @since 1.2.0 |
| 878 | * @access public |
| 879 | * @static |
| 880 | * |
| 881 | * @param int $template_id The template ID. |
| 882 | * |
| 883 | * @return object|\WP_Error The template content. |
| 884 | */ |
| 885 | public static function shoppress_get_template_data($template_id) |
| 886 | { |
| 887 | $url = self::$api_url . 'template/template-' . $template_id['template_id'] . '.json'; |
| 888 | |
| 889 | $response = wp_remote_post($url, array('timeout' => 25)); |
| 890 | |
| 891 | if (is_wp_error($response)) { |
| 892 | // @codingStandardsIgnoreStart WordPress.XSS.EscapeOutput. |
| 893 | wp_die($response, [ |
| 894 | 'back_link' => true, |
| 895 | ]); |
| 896 | // @codingStandardsIgnoreEnd WordPress.XSS.EscapeOutput. |
| 897 | } |
| 898 | |
| 899 | $body = wp_remote_retrieve_body($response); |
| 900 | $response_code = (int) wp_remote_retrieve_response_code($response); |
| 901 | |
| 902 | if (! $response_code) { |
| 903 | return new \WP_Error(500, 'No Response'); |
| 904 | } |
| 905 | |
| 906 | // Server sent a success message without content. |
| 907 | if ('null' === $body) { |
| 908 | $body = true; |
| 909 | } |
| 910 | |
| 911 | $as_array = true; |
| 912 | $body = json_decode($body, $as_array); |
| 913 | |
| 914 | if (false === $body) { |
| 915 | return new \WP_Error(422, 'Wrong Server Response'); |
| 916 | } |
| 917 | |
| 918 | if (200 !== $response_code) { |
| 919 | // In case $as_array = true. |
| 920 | $body = (object) $body; |
| 921 | |
| 922 | $message = isset($body->message) ? $body->message : wp_remote_retrieve_response_message($response); |
| 923 | $code = isset($body->code) ? $body->code : $response_code; |
| 924 | |
| 925 | return new \WP_Error($code, $message); |
| 926 | } |
| 927 | |
| 928 | $body['content'] = static::sanitize_elements($body['content']); |
| 929 | |
| 930 | // update images |
| 931 | $body = static::update_images($body); |
| 932 | |
| 933 | return $body; |
| 934 | } |
| 935 | |
| 936 | /** |
| 937 | * Render template. |
| 938 | * |
| 939 | * Library modal template. |
| 940 | * |
| 941 | * @since 1.2.0 |
| 942 | * @access public |
| 943 | * @static |
| 944 | * |
| 945 | * @return void |
| 946 | */ |
| 947 | public static function render_template() |
| 948 | { |
| 949 | ?> |
| 950 | <script type="text/template" id="tmpl-elementor-template-library-header-actions-pp"> |
| 951 | <div id="elementor-template-library-header-sync" class="elementor-templates-modal__header__item"> |
| 952 | <i class="eicon-sync" aria-hidden="true" title="<?php esc_attr_e('Sync Templates', 'shop-press'); ?>"></i> |
| 953 | <span class="elementor-screen-only"><?php echo esc_html__('Sync Templates', 'shop-press'); ?></span> |
| 954 | </div> |
| 955 | </script> |
| 956 | <script type="text/template" id="tmpl-elementor-templates-modal__header__logo_pp"> |
| 957 | <span class="elementor-templates-modal__header__logo__title">{{{ title }}}</span> |
| 958 | </script> |
| 959 | <script type="text/template" id="shoppress-tmpl-elementor-template-library-header-preview-pp"> |
| 960 | <div id="elementor-template-library-header-preview-insert-wrapper" class="elementor-templates-modal__header__item"> |
| 961 | {{{ shoppress_templates_lib.templates.layout.getTemplateActionButton( obj ) }}} |
| 962 | </div> |
| 963 | </script> |
| 964 | <script type="text/template" id="tmpl-elementor-template-library-templates-shoppress"> |
| 965 | <# |
| 966 | var activeSource = shoppress_templates_lib.templates.getFilter('source'); |
| 967 | #> |
| 968 | <div id="elementor-template-library-toolbar"> |
| 969 | <# if ( activeSource ) { |
| 970 | var activeType = shoppress_templates_lib.templates.getFilter('type'); |
| 971 | #> |
| 972 | <div id="elementor-template-library-filter-toolbar-remote" class="elementor-template-library-filter-toolbar"> |
| 973 | <# if ( 'new_page' === activeType ) { #> |
| 974 | <div id="elementor-template-library-order"> |
| 975 | <input type="radio" id="elementor-template-library-order-new" class="elementor-template-library-order-input" name="elementor-template-library-order" value="date"> |
| 976 | <label for="-new" class="elementor-template-library-order-label"><?php echo esc_html__('New', 'shop-press'); ?></label> |
| 977 | <input type="radio" id="elementor-template-library-order-trend" class="elementor-template-library-order-input" name="elementor-template-library-order" value="trendIndex"> |
| 978 | <label for="elementor-template-library-order-trend" class="elementor-template-library-order-label"><?php echo esc_html__('Trend', 'shop-press'); ?></label> |
| 979 | <input type="radio" id="elementor-template-library-order-popular" class="elementor-template-library-order-input" name="elementor-template-library-order" value="popularityIndex"> |
| 980 | <label for="elementor-template-library-order-popular" class="elementor-template-library-order-label"><?php echo esc_html__('Popular', 'shop-press'); ?></label> |
| 981 | </div> |
| 982 | <# } else { |
| 983 | var config = shoppress_templates_lib.templates.getConfig( activeType ); |
| 984 | if ( config.categories ) { #> |
| 985 | <div id="elementor-template-library-filter"> |
| 986 | <select id="elementor-template-library-filter-subtype" class="elementor-template-library-filter-select" data-elementor-filter="subtype"> |
| 987 | <option></option> |
| 988 | <# config.categories.forEach( function( category ) { |
| 989 | var selected = category === shoppress_templates_lib.templates.getFilter( 'subtype' ) ? ' selected' : ''; |
| 990 | #> |
| 991 | <option value="{{ category }}"{{{ selected }}}>{{{ category }}}</option> |
| 992 | <# } ); #> |
| 993 | </select> |
| 994 | </div> |
| 995 | <# } |
| 996 | } #> |
| 997 | <div id="elementor-template-library-my-favorites"> |
| 998 | <# var checked = shoppress_templates_lib.templates.getFilter( 'favorite' ) ? ' checked' : ''; #> |
| 999 | <input id="elementor-template-library-filter-my-favorites" type="checkbox"{{{ checked }}}> |
| 1000 | <label id="elementor-template-library-filter-my-favorites-label" for="elementor-template-library-filter-my-favorites"> |
| 1001 | <i class="eicon" aria-hidden="true"></i> |
| 1002 | <?php echo esc_html__('My Favorites', 'shop-press'); ?> |
| 1003 | </label> |
| 1004 | </div> |
| 1005 | </div> |
| 1006 | <# } #> |
| 1007 | <div id="elementor-template-library-filter-text-wrapper"> |
| 1008 | <label for="elementor-template-library-filter-text" class="elementor-screen-only"><?php echo esc_html__('Search Templates:', 'shop-press'); ?></label> |
| 1009 | <input id="elementor-template-library-filter-text" placeholder="<?php echo esc_attr__('Search', 'shop-press'); ?>"> |
| 1010 | <i class="eicon-search"></i> |
| 1011 | </div> |
| 1012 | </div> |
| 1013 | <# |
| 1014 | var is_kata = shoppress_templates_lib.is_kata ? true : false; |
| 1015 | if ( ! is_kata ) { |
| 1016 | #> |
| 1017 | <div id="shoppress-elementor-template-library-templates-kata-popup-notice"> |
| 1018 | <div id="shoppress-elementor-template-library-templates-kata-popup-notice-wrapper"> |
| 1019 | <i id="shoppress-elementor-template-library-templates-kata-popup-notice-close" class="eicon-close" aria-hidden="true"></i> |
| 1020 | <div id="shoppress-elementor-template-library-templates-kata-popup-notice-content"> |
| 1021 | <h3><?php esc_html_e('Please Note!', 'shop-press'); ?></h3> |
| 1022 | <p><?php esc_html_e('This template you\'re seeing in the image has been crafted using the Kata theme.', 'shop-press'); ?></p> |
| 1023 | <p><?php esc_html_e('As you may be aware, every theme possesses its own distinctive style, so it\'s possible that you\'ll encounter a divergent style upon import.', 'shop-press'); ?></p> |
| 1024 | </div> |
| 1025 | <div id="shoppress-elementor-template-library-templates-kata-popup-notice-actions"> |
| 1026 | <a href="#" data-action="import"><?php esc_html_e('Import Now', 'shop-press'); ?></a> |
| 1027 | <a href="#" data-action="cancel"><?php esc_html_e('Cancel', 'shop-press'); ?></a> |
| 1028 | <a href="https://wordpress.org/themes/kata/" data-action="get-kata" target="_blank"><?php esc_html_e('Get Kata Theme', 'shop-press'); ?></a> |
| 1029 | </div> |
| 1030 | </div> |
| 1031 | </div> |
| 1032 | <# } #> |
| 1033 | |
| 1034 | <div id="elementor-template-library-templates-container"></div> |
| 1035 | |
| 1036 | <# if ( 'content' === activeSource ) { #> |
| 1037 | <div id="elementor-template-library-footer-banner"> |
| 1038 | <img class="elementor-nerd-box-icon" src="<?php echo esc_url(ELEMENTOR_ASSETS_URL . 'images/information.svg'); ?>" /> |
| 1039 | <div class="elementor-excerpt"><?php echo esc_html__('Stay tuned! More awesome templates coming real soon.', 'shop-press'); ?></div> |
| 1040 | </div> |
| 1041 | <# } #> |
| 1042 | </script> |
| 1043 | <script type="text/template" id="shoppress-tmpl-elementor-template-library-template-pp"> |
| 1044 | <div class="elementor-template-library-template-body"> |
| 1045 | <# if ( 'page' === type ) { #> |
| 1046 | <div class="elementor-template-library-template-screenshot" style="background-image: url({{ thumbnail }});"></div> |
| 1047 | <# } else { #> |
| 1048 | <img src="{{ thumbnail }}"> |
| 1049 | <# } #> |
| 1050 | <div class="elementor-template-library-template-preview"> |
| 1051 | <i class="eicon-zoom-in-bold" aria-hidden="true"></i> |
| 1052 | </div> |
| 1053 | </div> |
| 1054 | <div class="elementor-template-library-template-footer"> |
| 1055 | {{{ shoppress_templates_lib.templates.layout.getTemplateActionButton( obj ) }}} |
| 1056 | <div class="elementor-template-library-template-name">{{{ title }}} - {{{ type }}}</div> |
| 1057 | <div class="elementor-template-library-favorite"> |
| 1058 | <input id="elementor-template-library-template-{{ template_id }}-favorite-input" class="elementor-template-library-template-favorite-input" type="checkbox"{{ favorite ? " checked" : "" }}> |
| 1059 | <label for="elementor-template-library-template-{{ template_id }}-favorite-input" class="elementor-template-library-template-favorite-label"> |
| 1060 | <i class="eicon-heart-o" aria-hidden="true"></i> |
| 1061 | <span class="elementor-screen-only"><?php echo esc_html__('Favorite', 'shop-press'); ?></span> |
| 1062 | </label> |
| 1063 | </div> |
| 1064 | </div> |
| 1065 | </script> |
| 1066 | <script type="text/template" id="tmpl-elementor-template-library-get-pro-button-pp"> |
| 1067 | <a class="elementor-template-library-template-action elementor-button elementor-go-pro" href="https://powerpackelements.com/pricing/?utm_source=panel-library&utm_campaign=gopro&utm_medium=wp-dash" target="_blank"> |
| 1068 | <i class="eicon-external-link-square" aria-hidden="true"></i> |
| 1069 | <span class="elementor-button-title"><?php echo esc_html(__('Go Pro', 'shop-press')); ?></span> |
| 1070 | </a> |
| 1071 | </script> |
| 1072 | <script type="text/template" id="tmpl-elementor-pro-template-library-activate-license-button-pp"> |
| 1073 | <a class="elementor-template-library-template-action elementor-button elementor-go-pro" href="#" target="_blank"> |
| 1074 | <i class="eicon-external-link-square"></i> |
| 1075 | <span class="elementor-button-title"><?php esc_html_e('Activate License', 'shop-press'); ?></span> |
| 1076 | </a> |
| 1077 | </script> |
| 1078 | <?php |
| 1079 | } |
| 1080 | } |
| 1081 | |
| 1082 | TemplatesLib::init(); |
| 1083 |