PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.4.1
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.4.1
3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 All 111 releases
← All changes | includes/Utils/Helper.php +358 -74 3.0.33.4.1 View file →
@@ -1,11 +1,15 @@
1 1 <?php
2 +
2 3 namespace Templately\Utils;
3 4
5 +use Elementor\Plugin;
6 +use Templately\Core\Importer\Utils\Utils;
4 7 use WP_Error;
5 8 use WP_REST_Response;
6 9 use function get_plugins;
7 10 use function is_plugin_active;
11 +
8 12 /**
9 13 * Utility Helper for Templately
10 14 *
11 15 * This class contains some helper functions for easy access.
@@ -12,31 +16,55 @@
12 16 *
13 17 * @since 1.0.0
14 18 */
15 19 class Helper extends Base {
16 - /**
17 - * Get installed WordPress Plugin List
18 - * @return array
19 - */
20 - public static function get_plugins(){
21 - if( ! function_exists( 'get_plugins' ) ) {
22 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
23 - }
24 - return get_plugins();
25 - }
20 + /**
21 + * Check if development API should be used
22 + *
23 + * This method maintains backward compatibility by checking both TEMPLATELY_DEV_API
24 + * and falling back to TEMPLATELY_DEV if needed. This fallback logic should NOT be
25 + * removed as it ensures existing setups continue to work.
26 + *
27 + * @return bool True if development API should be used
28 + */
29 + public static function is_dev_api(){
30 + // Primary check: TEMPLATELY_DEV_API constant
31 + if ( defined( 'TEMPLATELY_DEV_API' ) ) {
32 + return constant( 'TEMPLATELY_DEV_API' );
33 + }
26 34
27 - /**
28 - * Get installed WordPress Plugin List
29 - * @return boolean
30 - */
31 - public static function is_plugin_active( $plugin ){
32 - if( ! function_exists( 'is_plugin_active' ) ) {
33 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
34 - }
35 - return is_plugin_active( $plugin );
36 - }
35 + // Fallback: Legacy TEMPLATELY_DEV constant for backward compatibility
36 + return defined( 'TEMPLATELY_DEV' ) && constant( 'TEMPLATELY_DEV' );
37 + }
37 38
38 - /**
39 + /**
40 + * Get installed WordPress Plugin List
41 + * @return array
42 + */
43 + public static function get_plugins() {
44 + if (! function_exists('get_plugins')) {
45 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
46 + }
47 + return get_plugins();
48 + }
49 + public static function is_plugins_installed($plugin_file) {
50 + $_plugins = self::get_plugins();
51 + $is_installed = isset($_plugins[$plugin_file]);
52 + return $is_installed;
53 + }
54 +
55 + /**
56 + * Get installed WordPress Plugin List
57 + * @return boolean
58 + */
59 + public static function is_plugin_active($plugin) {
60 + if (! function_exists('is_plugin_active')) {
61 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
62 + }
63 + return is_plugin_active($plugin);
64 + }
65 +
66 + /**
39 67 * Collect IP from request.
40 68 *
41 69 * @return string
42 70 */
@@ -41,37 +69,131 @@
41 69 * @return string
42 70 */
43 71 public static function get_ip() {
44 72 $ip = '127.0.0.1'; // Local IP
45 - if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
73 + if (! empty($_SERVER['HTTP_CLIENT_IP'])) {
46 74 $ip = $_SERVER['HTTP_CLIENT_IP'];
47 - } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
75 + } elseif (! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
48 76 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
49 77 } else {
50 - $ip = ! empty( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : $ip;
78 + $ip = ! empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : $ip;
51 79 }
52 80
53 - return sanitize_text_field( $ip );
81 + return sanitize_text_field($ip);
54 82 }
55 83
56 - /**
57 - * Get views for front-end display
58 - *
59 - * @param string $name it will be file name only from the view's folder.
60 - * @param array $data
61 - * @return void
62 - */
63 - public static function views( $name, $data = [] ){
64 - extract( $data );
65 - $helper = self::class;
66 - $file = TEMPLATELY_PATH . 'views/' . $name . '.php';
84 + /**
85 + * Get views for front-end display
86 + *
87 + * @param string $name it will be file name only from the view's folder.
88 + * @param array $data
89 + * @return void
90 + */
91 + public static function views($name, $data = []) {
92 + extract($data);
93 + $helper = self::class;
94 + $file = TEMPLATELY_PATH . 'views/' . $name . '.php';
67 95
68 - if( is_readable( $file ) ) {
69 - include_once $file;
70 - }
71 - }
96 + if (is_readable($file)) {
97 + include_once $file;
98 + }
99 + }
72 100
73 101 /**
102 + * Get API URL for Templately endpoints
103 + *
104 + * @param string $endpoint API endpoint path (e.g., 'v2/import/pack/123')
105 + * @return string Complete API URL
106 + */
107 + public static function get_api_url($endpoint): string {
108 + $base_url = self::is_dev_api() ? 'https://app.templately.dev' : 'https://app.templately.com';
109 + return "{$base_url}/api/{$endpoint}";
110 + }
111 +
112 + /**
113 + * Make a unified API request to Templately API
114 + *
115 + * @param string $method HTTP method (GET or POST)
116 + * @param string $api_url Complete API URL
117 + * @param array $body Request body data (for POST requests)
118 + * @param array $extra_headers Additional headers beyond the standard ones
119 + * @param int $timeout Request timeout in seconds (default: 30)
120 + * @return array|WP_Error Response array or WP_Error on failure
121 + */
122 + private static function make_api_request($method, $api_url, $body = [], $extra_headers = [], $timeout = 30) {
123 + $api_key = Options::get_instance()->get('api_key');
124 +
125 + $headers = [
126 + 'Authorization' => 'Bearer ' . $api_key,
127 + 'x-templately-ip' => self::get_ip(),
128 + 'x-templately-url' => home_url('/'),
129 + 'x-templately-version' => defined( 'TEMPLATELY_VERSION' ) ? constant( 'TEMPLATELY_VERSION' ) : '1.0.0',
130 + ];
131 +
132 + // Add Content-Type for POST requests
133 + if (strtoupper($method) === 'POST') {
134 + $headers['Content-Type'] = 'application/json';
135 + }
136 +
137 + // Merge additional headers
138 + $headers = array_merge($headers, $extra_headers);
139 +
140 + $args = [
141 + 'timeout' => $timeout,
142 + 'headers' => $headers,
143 + ];
144 +
145 + // Apply filter to allow network admin or other functionality to modify request args
146 + $args = apply_filters( 'templately_api_request_params', $args, $method, $api_url );
147 +
148 + // Add body for POST requests
149 + if (strtoupper($method) === 'POST') {
150 + $args['body'] = is_array($body) ? json_encode($body) : $body;
151 + }
152 +
153 + // Make the appropriate request
154 + if (strtoupper($method) === 'POST') {
155 + return wp_remote_post($api_url, $args);
156 + } else {
157 + return wp_remote_get($api_url, $args);
158 + }
159 + }
160 +
161 + /**
162 + * Make a GET request to Templately API
163 + *
164 + * @param string $endpoint API endpoint path (e.g., 'v2/import/pack/123')
165 + * @param array $query_params Query parameters as key-value pairs
166 + * @param array $extra_headers Additional headers beyond the standard ones
167 + * @param int $timeout Request timeout in seconds (default: 30)
168 + * @return array|WP_Error Response array or WP_Error on failure
169 + */
170 + public static function make_api_get_request($endpoint, $query_params = [], $extra_headers = [], $timeout = 30) {
171 + $api_url = self::get_api_url($endpoint);
172 +
173 + // Add query parameters if provided
174 + if (!empty($query_params)) {
175 + $api_url = add_query_arg($query_params, $api_url);
176 + }
177 +
178 + return self::make_api_request('GET', $api_url, [], $extra_headers, $timeout);
179 + }
180 +
181 + /**
182 + * Make a POST request to Templately API
183 + *
184 + * @param string $endpoint API endpoint path (e.g., 'v2/feedback/store')
185 + * @param array $body Request body data
186 + * @param array $extra_headers Additional headers beyond the standard ones
187 + * @param int $timeout Request timeout in seconds (default: 30)
188 + * @return array|WP_Error Response array or WP_Error on failure
189 + */
190 + public static function make_api_post_request($endpoint, $body = [], $extra_headers = [], $timeout = 30) {
191 + $api_url = self::get_api_url($endpoint);
192 + return self::make_api_request('POST', $api_url, $body, $extra_headers, $timeout);
193 + }
194 +
195 + /**
74 196 * Sanitize Helper
75 197 *
76 198 * @param mixed $value
77 199 * @param string $type
@@ -77,15 +199,15 @@
77 199 * @param string $type
78 200 *
79 201 * @return bool|string
80 202 */
81 - public static function sanitize( $value, $type = 'text' ){
82 - switch ( $type ) {
203 + public static function sanitize($value, $type = 'text') {
204 + switch ($type) {
83 205 case 'boolean':
84 - $sanitized_value = rest_sanitize_boolean( $value );
206 + $sanitized_value = rest_sanitize_boolean($value);
85 207 break;
86 208 default:
87 - $sanitized_value = sanitize_text_field( $value );
209 + $sanitized_value = sanitize_text_field($value);
88 210 break;
89 211 }
90 212
91 213 return $sanitized_value;
@@ -100,15 +222,18 @@
100 222 * @param integer $status
101 223 * @param array $additional_data
102 224 * @return WP_Error
103 225 */
104 - public static function error( $error_code, $error_message, $endpoint = '', $status = 500, $additional_data = [] ) {
226 + public static function error($error_code, $error_message, $endpoint = '', $status = 500, $additional_data = []) {
105 227 $additional_data['status'] = $status;
106 - if ( ! empty( $endpoint ) ) {
228 + if (! empty($endpoint)) {
107 229 $additional_data['endpoint'] = $endpoint;
108 230 }
231 + // Add browser padding to avoid browsers not serving small JSON responses
232 + $padding_length = 512;
233 + $additional_data['browser_padding'] = str_repeat(' ', $padding_length);
109 234
110 - return new WP_Error( $error_code, $error_message, $additional_data );
235 + return new WP_Error($error_code, $error_message, $additional_data);
111 236 }
112 237
113 238 /**
114 239 * API Response Formatter
@@ -115,10 +240,10 @@
115 240 *
116 241 * @param mixed $data
117 242 * @return WP_REST_Response
118 243 */
119 - public static function success( $data ) {
120 - return new WP_REST_Response( $data, 200 );
244 + public static function success($data) {
245 + return new WP_REST_Response($data, 200);
121 246 }
122 247
123 248 /**
124 249 * Normalize Favourites Data
@@ -128,42 +253,42 @@
128 253 * @param boolean $undo
129 254 *
130 255 * @return array
131 256 */
132 - public function normalizeFavourites( $favourites, $_favourites = [], $undo = false ){
133 - if( $undo ) {
134 - $_favourites[ $favourites['type'] ] = array_values(array_filter( $_favourites[ $favourites['type'] ], function( $item ) use( $favourites ) {
257 + public function normalizeFavourites($favourites, $_favourites = [], $undo = false) {
258 + if ($undo) {
259 + $_favourites[$favourites['type']] = array_values(array_filter($_favourites[$favourites['type']], function ($item) use ($favourites) {
135 260 return $item != $favourites['id'];
136 - } ));
261 + }));
137 262 return $_favourites;
138 263 }
139 264
140 - array_map( function( $item ) use ( &$_favourites) {
141 - if( ! is_null( $item ) ) {
265 + array_map(function ($item) use (&$_favourites) {
266 + if (! is_null($item)) {
142 267 $item = (array) $item;
143 - if ( isset( $_favourites[ $item['type'] ] ) ){
144 - $_favourites[ $item['type'] ][] = $item['id'];
268 + if (isset($_favourites[$item['type']])) {
269 + $_favourites[$item['type']][] = $item['id'];
145 270 } else {
146 - $_favourites[ $item['type'] ] = [ $item['id'] ];
271 + $_favourites[$item['type']] = [$item['id']];
147 272 }
148 273 }
149 274 return $_favourites;
150 - }, $favourites );
275 + }, $favourites);
151 276
152 277 return $_favourites;
153 278 }
154 279
155 - public function normalizeReviews( $favourites, $_favourites = [], $undo = false ){
156 - array_map( function( $item ) use ( &$_favourites) {
157 - if( ! is_null( $item ) ) {
280 + public function normalizeReviews($favourites, $_favourites = [], $undo = false) {
281 + array_map(function ($item) use (&$_favourites) {
282 + if (! is_null($item)) {
158 283 $item = (array) $item;
159 - if ( !isset( $_favourites[ $item['type'] ] ) ){
160 - $_favourites[ $item['type'] ] = [];
284 + if (!isset($_favourites[$item['type']])) {
285 + $_favourites[$item['type']] = [];
161 286 }
162 - $_favourites[ $item['type'] ][$item['type_id']] = $item['rating'];
287 + $_favourites[$item['type']][$item['type_id']] = $item['rating'];
163 288 }
164 289 return $_favourites;
165 - }, $favourites );
290 + }, $favourites);
166 291
167 292 return $_favourites;
168 293 }
169 294
@@ -172,10 +297,10 @@
172 297 *
173 298 * @param object $triggered_by
174 299 * @return void
175 300 */
176 - public static function trigger_error( $triggered_by, $method = 'get_instance' ){
177 - $class = get_class( $triggered_by );
301 + public static function trigger_error($triggered_by, $method = 'get_instance') {
302 + $class = get_class($triggered_by);
178 303 $trace = debug_backtrace(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
179 304 $file = $trace[0]['file'];
180 305 $line = $trace[0]['line'];
181 306 trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
@@ -186,14 +311,173 @@
186 311 *
187 312 * @param mixed $log
188 313 * @return void
189 314 */
190 - public static function log( $log ){
191 - if ( defined('WP_DEBUG_LOG') && WP_DEBUG_LOG === true ) {
192 - if ( is_array( $log ) || is_object( $log ) ) {
193 - error_log( print_r( $log, true ) );
315 + public static function log($log) {
316 + if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
317 + if (is_array($log) || is_object($log)) {
318 + error_log(print_r($log, true));
194 319 } else {
195 - error_log( $log );
320 + error_log($log ?: '');
196 321 }
197 322 }
198 323 }
199 -}
324 +
325 + public static function should_flush() {
326 + if (isset($_REQUEST['is_lightspeed']) && $_REQUEST['is_lightspeed'] === 'true') {
327 + return false;
328 + }
329 + return (!defined('TEMPLATELY_IGNORE_FLUSH_ALL') || !TEMPLATELY_IGNORE_FLUSH_ALL) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') === false;
330 + }
331 +
332 + public static function get_block_by_name($blocks, $search) {
333 + $queue = $blocks;
334 +
335 + while (!empty($queue)) {
336 + $current_block = array_shift($queue);
337 +
338 + if ($search === $current_block['blockName']) {
339 + return $current_block;
340 + }
341 +
342 + if (isset($current_block['innerBlocks'])) {
343 + // Add nested blocks to the end of the queue for processing
344 + $queue = array_merge($queue, $current_block['innerBlocks']);
345 + }
346 + }
347 +
348 + return false;
349 + }
350 +
351 + /**
352 + * Only checks if user can install/activate plugins
353 + *
354 + * @param [type] $cap
355 + * @param [type] ...$args
356 + * @return void
357 + */
358 + public static function current_user_can($cap, ...$args) {
359 + $user = wp_get_current_user();
360 +
361 + // Multisite super admin has all caps by definition, Unless specifically denied.
362 + if (is_multisite() && is_super_admin($user->ID)) {
363 + return true;
364 + }
365 +
366 + $caps = map_meta_cap($cap, $user->ID, ...$args);
367 +
368 + switch ($cap) {
369 + case 'install_plugins':
370 + case 'upload_plugins':
371 + $caps = ['install_plugins'];
372 + break;
373 + case 'install_themes':
374 + case 'upload_themes':
375 + $caps = ['install_themes'];
376 + break;
377 + case 'activate_plugins':
378 + case 'deactivate_plugins':
379 + case 'activate_plugin':
380 + case 'deactivate_plugin':
381 + $caps = ['activate_plugins'];
382 + break;
383 + default:
384 + break;
385 + }
386 +
387 + // Maintain BC for the argument passed to the "user_has_cap" filter.
388 + $args = array_merge(array($cap, $user->ID), $args);
389 +
390 + /**
391 + * See WP_User::has_cap() for description.
392 + */
393 + $capabilities = apply_filters('user_has_cap', $user->allcaps, $caps, $args, $user);
394 +
395 + // Everyone is allowed to exist.
396 + $capabilities['exist'] = true;
397 +
398 + // Nobody is allowed to do things they are not allowed to do.
399 + unset($capabilities['do_not_allow']);
400 +
401 + // Must have ALL requested caps.
402 + foreach ((array) $caps as $cap) {
403 + if (empty($capabilities[$cap])) {
404 + return false;
405 + }
406 + }
407 +
408 + return true;
409 + }
410 +
411 + /**
412 + * Calculates the elapsed time and checks if it is close to the maximum execution time.
413 + * Returns true if the script should exit to avoid exceeding the limit.
414 + *
415 + * @return bool True if the script should exit, false otherwise.
416 + */
417 + public static function fsi_should_exit() {
418 + if (defined('TEMPLATELY_START_TIME') && ini_get('max_execution_time')) {
419 + $max_time = ini_get('max_execution_time');
420 + $elapsed = microtime(true) - TEMPLATELY_START_TIME;
421 + $delay = max(5, $max_time * 20 / 100);
422 +
423 + // Check if elapsed time is close to max execution time
424 + if ($max_time - $elapsed <= $delay) {
425 + return ['max_time' => $max_time, 'elapsed' => $elapsed, 'delay' => $delay];
426 + }
427 + }
428 + return false;
429 + }
430 +
431 + /**
432 + * Enable Elementor Container
433 + * This function will enable the Elementor Container feature.
434 + * Without this feature, some of the templates may not work properly.
435 + *
436 + * @return boolean
437 + */
438 + public static function enable_elementor_container() {
439 + if (class_exists('Elementor\Plugin')) {
440 + $control_name = Plugin::instance()->experiments->get_feature_option_key('container');
441 + if (get_option($control_name) === 'inactive') {
442 + update_option($control_name, 'active');
443 + return true;
444 + }
445 + }
446 + return false;
447 + }
448 +
449 + /**
450 + * Undocumented function
451 + *
452 + * @param [type] $args
453 + * @param [type] $defaults
454 + * @return array
455 + */
456 + public static function recursive_wp_parse_args($args, $defaults) {
457 + $args = (array) $args;
458 + $defaults = (array) $defaults;
459 + $r = $defaults;
460 + foreach ($args as $key => $value) {
461 + if (is_array($value) && isset($r[$key])) {
462 + // also handle numeric array. if both $value and $r[ $key ] are numeric array. wp_is_numeric_array()
463 + if (wp_is_numeric_array($value) && wp_is_numeric_array($r[$key])) {
464 + foreach ($value as $k => $v) {
465 + if (!in_array($v, $r[$key])) {
466 + if (!isset($r[$key][$k])) {
467 + $r[$key][$k] = $v;
468 + } else {
469 + $r[$key][] = $v;
470 + }
471 + }
472 + }
473 + } else {
474 + $r[$key] = self::recursive_wp_parse_args($value, $r[$key]);
475 + }
476 + } else {
477 + $r[$key] = $value;
478 + }
479 + }
480 + return $r;
481 + }
482 +
483 +}