PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.4.7
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.4.7
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
templately / includes / Utils / Helper.php

Helper.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.4.7, at includes/Utils/Helper.php

571 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Utils;
4
5 use Elementor\Plugin;
6 use Templately\Core\Importer\Utils\Utils;
7 use WP_Error;
8 use WP_REST_Response;
9 use function get_plugins;
10 use function is_plugin_active;
11
12 /**
13 * Utility Helper for Templately
14 *
15 * This class contains some helper functions for easy access.
16 *
17 * @since 1.0.0
18 */
19 class Helper extends Base {
20 /**
21 * Check if development API should be used
22 *
23 * @return bool True if development API should be used
24 */
25 public static function is_dev_api(){
26 // Only check TEMPLATELY_DEV_API constant - no fallback mechanisms
27 return defined( 'TEMPLATELY_DEV_API' ) && constant( 'TEMPLATELY_DEV_API' );
28 }
29
30 /**
31 * Get installed WordPress Plugin List
32 * @return array
33 */
34 public static function get_plugins() {
35 if (! function_exists('get_plugins')) {
36 require_once ABSPATH . 'wp-admin/includes/plugin.php';
37 }
38 return get_plugins();
39 }
40 public static function is_plugins_installed($plugin_file) {
41 $_plugins = self::get_plugins();
42 $is_installed = isset($_plugins[$plugin_file]);
43 return $is_installed;
44 }
45
46 /**
47 * Get installed WordPress Plugin List
48 * @return boolean
49 */
50 public static function is_plugin_active($plugin) {
51 if (! function_exists('is_plugin_active')) {
52 require_once ABSPATH . 'wp-admin/includes/plugin.php';
53 }
54 return is_plugin_active($plugin);
55 }
56
57 /**
58 * Collect IP from request.
59 *
60 * @return string
61 */
62 public static function get_ip() {
63 $ip = '127.0.0.1'; // Local IP
64 if (! empty($_SERVER['HTTP_CLIENT_IP'])) {
65 $ip = $_SERVER['HTTP_CLIENT_IP'];
66 } elseif (! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
67 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
68 } else {
69 $ip = ! empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : $ip;
70 }
71
72 return sanitize_text_field($ip);
73 }
74
75 /**
76 * Get views for front-end display
77 *
78 * @param string $name it will be file name only from the view's folder.
79 * @param array $data
80 * @return void
81 */
82 public static function views($name, $data = []) {
83 extract($data);
84 $helper = self::class;
85 $file = TEMPLATELY_PATH . 'views/' . $name . '.php';
86
87 if (is_readable($file)) {
88 include_once $file;
89 }
90 }
91
92 /**
93 * Get API URL for Templately endpoints
94 *
95 * @param string $endpoint API endpoint path (e.g., 'v2/import/pack/123')
96 * @return string Complete API URL
97 */
98 public static function get_api_url($endpoint): string {
99 $base_url = self::is_dev_api() ? 'https://app.templately.dev' : 'https://app.templately.com';
100 return "{$base_url}/api/{$endpoint}";
101 }
102
103 /**
104 * Make a unified API request to Templately API
105 *
106 * @param string $method HTTP method (GET or POST)
107 * @param string $api_url Complete API URL
108 * @param array $body Request body data (for POST requests)
109 * @param array $extra_headers Additional headers beyond the standard ones
110 * @param int $timeout Request timeout in seconds (default: 30)
111 * @return array|WP_Error Response array or WP_Error on failure
112 */
113 private static function make_api_request($method, $api_url, $body = [], $extra_headers = [], $timeout = 30) {
114 $api_key = Options::get_instance()->get('api_key');
115
116 $headers = [
117 'Authorization' => 'Bearer ' . $api_key,
118 'x-templately-ip' => self::get_ip(),
119 'x-templately-url' => home_url('/'),
120 'x-templately-version' => defined( 'TEMPLATELY_VERSION' ) ? constant( 'TEMPLATELY_VERSION' ) : '1.0.0',
121 ];
122
123 // Add Content-Type for POST requests
124 if (strtoupper($method) === 'POST') {
125 $headers['Content-Type'] = 'application/json';
126 }
127
128 // Merge additional headers
129 $headers = array_merge($headers, $extra_headers);
130
131 $args = [
132 'timeout' => $timeout,
133 'headers' => $headers,
134 ];
135
136 // Apply filter to allow network admin or other functionality to modify request args
137 $args = apply_filters( 'templately_api_request_params', $args, $method, $api_url );
138
139 // Add body for POST requests
140 if (strtoupper($method) === 'POST') {
141 $args['body'] = is_array($body) ? json_encode($body) : $body;
142 }
143
144 // Make the appropriate request
145 if (strtoupper($method) === 'POST') {
146 $response = wp_remote_post($api_url, $args);
147 } else {
148 $response = wp_remote_get($api_url, $args);
149 }
150
151 // Check for verification header in the response
152 self::check_verification_header($response);
153
154 return $response;
155 }
156
157 /**
158 * Make a GET request to Templately API
159 *
160 * @param string $endpoint API endpoint path (e.g., 'v2/import/pack/123')
161 * @param array $query_params Query parameters as key-value pairs
162 * @param array $extra_headers Additional headers beyond the standard ones
163 * @param int $timeout Request timeout in seconds (default: 30)
164 * @return array|WP_Error Response array or WP_Error on failure
165 */
166 public static function make_api_get_request($endpoint, $query_params = [], $extra_headers = [], $timeout = 30) {
167 $api_url = self::get_api_url($endpoint);
168
169 // Add query parameters if provided
170 if (!empty($query_params)) {
171 $api_url = add_query_arg($query_params, $api_url);
172 }
173
174 return self::make_api_request('GET', $api_url, [], $extra_headers, $timeout);
175 }
176
177 /**
178 * Make a POST request to Templately API
179 *
180 * @param string $endpoint API endpoint path (e.g., 'v2/feedback/store')
181 * @param array $body Request body data
182 * @param array $extra_headers Additional headers beyond the standard ones
183 * @param int $timeout Request timeout in seconds (default: 30)
184 * @return array|WP_Error Response array or WP_Error on failure
185 */
186 public static function make_api_post_request($endpoint, $body = [], $extra_headers = [], $timeout = 30) {
187 $api_url = self::get_api_url($endpoint);
188 return self::make_api_request('POST', $api_url, $body, $extra_headers, $timeout);
189 }
190
191 /**
192 * Sanitize Helper
193 *
194 * @param mixed $value
195 * @param string $type
196 *
197 * @return bool|string
198 */
199 public static function sanitize($value, $type = 'text') {
200 switch ($type) {
201 case 'boolean':
202 $sanitized_value = rest_sanitize_boolean($value);
203 break;
204 default:
205 $sanitized_value = sanitize_text_field($value);
206 break;
207 }
208
209 return $sanitized_value;
210 }
211
212 /**
213 * Check for X-Templately-Verified header and update user verification status
214 *
215 * @param array|WP_Error $response The HTTP response array from wp_remote_get/wp_remote_post
216 * @return void
217 */
218 public static function check_verification_header($response) {
219 // Only process if response is not a WP_Error and contains headers
220 if (is_wp_error($response)) {
221 return;
222 }
223
224 // Retrieve the X-Templately-Verified header
225 $verification_header = wp_remote_retrieve_header($response, 'X-Templately-Verified');
226
227 // Check if header exists and has a truthy value
228 if (!empty($verification_header) && filter_var($verification_header, FILTER_VALIDATE_BOOLEAN)) {
229 try {
230 // Get current user data
231 $options = Options::get_instance();
232 $user = $options->get('user');
233
234 // Only update if user data exists and is not already verified
235 if (!empty($user) && is_array($user) && empty($user['is_verified'])) {
236 // Set verification flag
237 $user['is_verified'] = true;
238
239 // Save updated user data
240 $options->set('user', $user);
241
242 }
243
244 if (!empty($user['is_verified'])){
245 if(!headers_sent()){
246 header( 'X-Templately-Verified: true' );
247 if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
248 self::log('User verification status already updated via X-Templately-Verified header');
249 }
250 }
251
252 return true;
253 }
254 } catch (\Exception $e) {
255 // Log error if debug logging is enabled
256 if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
257 self::log('Error updating user verification status: ' . $e->getMessage());
258 }
259 }
260 }
261
262 return false;
263 }
264
265 /**
266 * API Error Formatter
267 *
268 * @param int $error_code
269 * @param mixed $error_message
270 * @param string $endpoint
271 * @param integer $status
272 * @param array $additional_data
273 * @return WP_Error
274 */
275 public static function error($error_code, $error_message, $endpoint = '', $status = 500, $additional_data = []) {
276 $additional_data['status'] = $status;
277 if (! empty($endpoint)) {
278 $additional_data['endpoint'] = $endpoint;
279 }
280 // Add browser padding to avoid browsers not serving small JSON responses
281 $padding_length = 512;
282 $additional_data['browser_padding'] = str_repeat(' ', $padding_length);
283
284 return new WP_Error($error_code, $error_message, $additional_data);
285 }
286
287 /**
288 * API Response Formatter
289 *
290 * @param mixed $data
291 * @return WP_REST_Response
292 */
293 public static function success($data) {
294 return new WP_REST_Response($data, 200);
295 }
296
297 /**
298 * Normalize Favourites Data
299 *
300 * @param array $favourites
301 * @param array $_favourites
302 * @param boolean $undo
303 *
304 * @return array
305 */
306 public function normalizeFavourites($favourites, $_favourites = [], $undo = false) {
307 if ($undo) {
308 $_favourites[$favourites['type']] = array_values(array_filter($_favourites[$favourites['type']], function ($item) use ($favourites) {
309 return $item != $favourites['id'];
310 }));
311 return $_favourites;
312 }
313
314 array_map(function ($item) use (&$_favourites) {
315 if (! is_null($item)) {
316 $item = (array) $item;
317 if (isset($_favourites[$item['type']])) {
318 $_favourites[$item['type']][] = $item['id'];
319 } else {
320 $_favourites[$item['type']] = [$item['id']];
321 }
322 }
323 return $_favourites;
324 }, $favourites);
325
326 return $_favourites;
327 }
328
329 public function normalizeReviews($favourites, $_favourites = [], $undo = false) {
330 array_map(function ($item) use (&$_favourites) {
331 if (! is_null($item)) {
332 $item = (array) $item;
333 if (!isset($_favourites[$item['type']])) {
334 $_favourites[$item['type']] = [];
335 }
336 $_favourites[$item['type']][$item['type_id']] = $item['rating'];
337 }
338 return $_favourites;
339 }, $favourites);
340
341 return $_favourites;
342 }
343
344 /**
345 * Trigger Error
346 *
347 * @param object $triggered_by
348 * @return void
349 */
350 public static function trigger_error($triggered_by, $method = 'get_instance') {
351 $class = get_class($triggered_by);
352 $trace = debug_backtrace(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
353 $file = $trace[0]['file'];
354 $line = $trace[0]['line'];
355 trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
356 }
357
358 /**
359 * Printing Error Logs in debug.log file.
360 *
361 * @param mixed $log The data to log
362 * @param string $context Optional context for categorizing log entries
363 * @param string $level Optional log level (debug, info, warning, error)
364 * @return void
365 */
366 public static function log($log, $context = '', $level = 'info') {
367 // Allow complete override of logging behavior
368 $override_result = apply_filters('templately_log_override', null, $log, $context, $level);
369 if ($override_result !== null) {
370 return;
371 }
372
373 // Only log if WP_DEBUG_LOG is enabled
374 if (!defined('WP_DEBUG_LOG') || !WP_DEBUG_LOG) {
375 return;
376 }
377
378 // Format the log message
379 $formatted_message = self::format_log_message($log, $context, $level);
380
381 // Write to error log
382 error_log($formatted_message);
383 }
384
385 /**
386 * Format log message with context and level
387 *
388 * @param mixed $log The data to log
389 * @param string $context Context for categorizing log entries
390 * @param string $level Log level
391 * @return string Formatted log message
392 */
393 private static function format_log_message($log, $context = '', $level = 'info') {
394 // Convert arrays and objects to readable format
395 if (is_array($log) || is_object($log)) {
396 $log_content = print_r($log, true);
397 } else {
398 $log_content = (string) ($log ?: '');
399 }
400
401 // Build the formatted message
402 $timestamp = current_time('Y-m-d H:i:s');
403 $level_upper = strtoupper($level);
404
405 if (!empty($context)) {
406 return "[{$timestamp}] [{$level_upper}] [{$context}] {$log_content}";
407 } else {
408 return "[{$timestamp}] [{$level_upper}] {$log_content}";
409 }
410 }
411
412 public static function should_flush() {
413 if (isset($_REQUEST['is_lightspeed']) && $_REQUEST['is_lightspeed'] === 'true') {
414 return false;
415 }
416 return (!defined('TEMPLATELY_IGNORE_FLUSH_ALL') || !TEMPLATELY_IGNORE_FLUSH_ALL) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') === false;
417 }
418
419 public static function get_block_by_name($blocks, $search) {
420 $queue = $blocks;
421
422 while (!empty($queue)) {
423 $current_block = array_shift($queue);
424
425 if ($search === $current_block['blockName']) {
426 return $current_block;
427 }
428
429 if (isset($current_block['innerBlocks'])) {
430 // Add nested blocks to the end of the queue for processing
431 $queue = array_merge($queue, $current_block['innerBlocks']);
432 }
433 }
434
435 return false;
436 }
437
438 /**
439 * Only checks if user can install/activate plugins
440 *
441 * @param [type] $cap
442 * @param [type] ...$args
443 * @return void
444 */
445 public static function current_user_can($cap, ...$args) {
446 $user = wp_get_current_user();
447
448 // Multisite super admin has all caps by definition, Unless specifically denied.
449 if (is_multisite() && is_super_admin($user->ID)) {
450 return true;
451 }
452
453 $caps = map_meta_cap($cap, $user->ID, ...$args);
454
455 switch ($cap) {
456 case 'install_plugins':
457 case 'upload_plugins':
458 $caps = ['install_plugins'];
459 break;
460 case 'install_themes':
461 case 'upload_themes':
462 $caps = ['install_themes'];
463 break;
464 case 'activate_plugins':
465 case 'deactivate_plugins':
466 case 'activate_plugin':
467 case 'deactivate_plugin':
468 $caps = ['activate_plugins'];
469 break;
470 default:
471 break;
472 }
473
474 // Maintain BC for the argument passed to the "user_has_cap" filter.
475 $args = array_merge(array($cap, $user->ID), $args);
476
477 /**
478 * See WP_User::has_cap() for description.
479 */
480 $capabilities = apply_filters('user_has_cap', $user->allcaps, $caps, $args, $user);
481
482 // Everyone is allowed to exist.
483 $capabilities['exist'] = true;
484
485 // Nobody is allowed to do things they are not allowed to do.
486 unset($capabilities['do_not_allow']);
487
488 // Must have ALL requested caps.
489 foreach ((array) $caps as $cap) {
490 if (empty($capabilities[$cap])) {
491 return false;
492 }
493 }
494
495 return true;
496 }
497
498 /**
499 * Calculates the elapsed time and checks if it is close to the maximum execution time.
500 * Returns true if the script should exit to avoid exceeding the limit.
501 *
502 * @return bool True if the script should exit, false otherwise.
503 */
504 public static function fsi_should_exit() {
505 if (defined('TEMPLATELY_START_TIME') && ini_get('max_execution_time')) {
506 $max_time = ini_get('max_execution_time');
507 $elapsed = microtime(true) - TEMPLATELY_START_TIME;
508 $delay = max(5, $max_time * 20 / 100);
509
510 // Check if elapsed time is close to max execution time
511 if ($max_time - $elapsed <= $delay) {
512 return ['max_time' => $max_time, 'elapsed' => $elapsed, 'delay' => $delay];
513 }
514 }
515 return false;
516 }
517
518 /**
519 * Enable Elementor Container
520 * This function will enable the Elementor Container feature.
521 * Without this feature, some of the templates may not work properly.
522 *
523 * @return boolean
524 */
525 public static function enable_elementor_container() {
526 if (class_exists('Elementor\Plugin')) {
527 $control_name = Plugin::instance()->experiments->get_feature_option_key('container');
528 if (get_option($control_name) !== 'active') {
529 update_option($control_name, 'active');
530 return true;
531 }
532 }
533 return false;
534 }
535
536 /**
537 * Undocumented function
538 *
539 * @param [type] $args
540 * @param [type] $defaults
541 * @return array
542 */
543 public static function recursive_wp_parse_args($args, $defaults) {
544 $args = (array) $args;
545 $defaults = (array) $defaults;
546 $r = $defaults;
547 foreach ($args as $key => $value) {
548 if (is_array($value) && isset($r[$key])) {
549 // also handle numeric array. if both $value and $r[ $key ] are numeric array. wp_is_numeric_array()
550 if (wp_is_numeric_array($value) && wp_is_numeric_array($r[$key])) {
551 foreach ($value as $k => $v) {
552 if (!in_array($v, $r[$key])) {
553 if (!isset($r[$key][$k])) {
554 $r[$key][$k] = $v;
555 } else {
556 $r[$key][] = $v;
557 }
558 }
559 }
560 } else {
561 $r[$key] = self::recursive_wp_parse_args($value, $r[$key]);
562 }
563 } else {
564 $r[$key] = $value;
565 }
566 }
567 return $r;
568 }
569
570 }
571