PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.2.4
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.2.4
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 +76 -544 3.7.23.2.4 View file →
@@ -1,15 +1,12 @@
1 1 <?php
2 -
3 2 namespace Templately\Utils;
4 3
5 4 use Elementor\Plugin;
6 -use Templately\Core\Importer\Utils\Utils;
7 5 use WP_Error;
8 6 use WP_REST_Response;
9 7 use function get_plugins;
10 8 use function is_plugin_active;
11 -
12 9 /**
13 10 * Utility Helper for Templately
14 11 *
15 12 * This class contains some helper functions for easy access.
@@ -17,30 +14,20 @@
17 14 * @since 1.0.0
18 15 */
19 16 class Helper extends Base {
20 17 /**
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 18 * Get installed WordPress Plugin List
32 19 * @return array
33 20 */
34 - public static function get_plugins() {
35 - if (! function_exists('get_plugins')) {
21 + public static function get_plugins(){
22 + if( ! function_exists( 'get_plugins' ) ) {
36 23 require_once ABSPATH . 'wp-admin/includes/plugin.php';
37 24 }
38 25 return get_plugins();
39 26 }
40 - public static function is_plugins_installed($plugin_file) {
27 + public static function is_plugins_installed($plugin_file){
41 28 $_plugins = self::get_plugins();
42 - $is_installed = isset($_plugins[$plugin_file]);
29 + $is_installed = isset( $_plugins[ $plugin_file ] );
43 30 return $is_installed;
44 31 }
45 32
46 33 /**
@@ -46,59 +33,34 @@
46 33 /**
47 34 * Get installed WordPress Plugin List
48 35 * @return boolean
49 36 */
50 - public static function is_plugin_active($plugin) {
51 - if (! function_exists('is_plugin_active')) {
37 + public static function is_plugin_active( $plugin ){
38 + if( ! function_exists( 'is_plugin_active' ) ) {
52 39 require_once ABSPATH . 'wp-admin/includes/plugin.php';
53 40 }
54 - return is_plugin_active($plugin);
41 + return is_plugin_active( $plugin );
55 42 }
56 43
57 44 /**
58 45 * Collect IP from request.
59 46 *
60 - * Prefers REMOTE_ADDR since it cannot be spoofed by the client. When it is
61 - * a private/reserved address (reverse proxy, Docker bridge gateway like
62 - * 192.168.65.1, local dev), the forwarded headers are scanned for the first
63 - * public IP. If nothing public is found, the request is local: 127.0.0.1.
64 - *
65 47 * @return string
66 48 */
67 49 public static function get_ip() {
68 - $remote_addr = ! empty($_SERVER['REMOTE_ADDR']) ? sanitize_text_field($_SERVER['REMOTE_ADDR']) : '';
69 -
70 - if (self::is_public_ip($remote_addr)) {
71 - return $remote_addr;
50 + $ip = '127.0.0.1'; // Local IP
51 + if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
52 + $ip = $_SERVER['HTTP_CLIENT_IP'];
53 + } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
54 + $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
55 + } else {
56 + $ip = ! empty( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : $ip;
72 57 }
73 58
74 - foreach (['HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP'] as $header) {
75 - if (empty($_SERVER[$header])) {
76 - continue;
77 - }
78 - $candidates = explode(',', sanitize_text_field($_SERVER[$header]));
79 - foreach ($candidates as $candidate) {
80 - $candidate = trim($candidate);
81 - if (self::is_public_ip($candidate)) {
82 - return $candidate;
83 - }
84 - }
85 - }
86 -
87 - return '127.0.0.1';
59 + return sanitize_text_field( $ip );
88 60 }
89 61
90 62 /**
91 - * Check whether a string is a valid public (non-private, non-reserved) IP.
92 - *
93 - * @param string $ip
94 - * @return bool
95 - */
96 - private static function is_public_ip($ip): bool {
97 - return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
98 - }
99 -
100 - /**
101 63 * Get views for front-end display
102 64 *
103 65 * @param string $name it will be file name only from the view's folder.
104 66 * @param array $data
@@ -103,143 +65,19 @@
103 65 * @param string $name it will be file name only from the view's folder.
104 66 * @param array $data
105 67 * @return void
106 68 */
107 - public static function views($name, $data = []) {
108 - extract($data);
69 + public static function views( $name, $data = [] ){
70 + extract( $data );
109 71 $helper = self::class;
110 72 $file = TEMPLATELY_PATH . 'views/' . $name . '.php';
111 73
112 - if (is_readable($file)) {
74 + if( is_readable( $file ) ) {
113 75 include_once $file;
114 76 }
115 77 }
116 78
117 79 /**
118 - * Get API URL for Templately endpoints
119 - *
120 - * @param string $endpoint API endpoint path (e.g., 'v2/import/pack/123')
121 - * @return string Complete API URL
122 - */
123 - public static function get_api_url($endpoint): string {
124 - $base_url = self::is_dev_api() ? 'https://app.templately.dev' : 'https://app.templately.com';
125 -
126 - /**
127 - * Filter the base URL for development API
128 - *
129 - * @since 3.5.0
130 - * @param string $base_url The default base URL
131 - */
132 - $base_url = apply_filters('templately_dev_api_base_url', $base_url);
133 -
134 - return "{$base_url}/api/{$endpoint}";
135 - }
136 -
137 - /**
138 - * Make a unified API request to Templately API
139 - *
140 - * @param string $method HTTP method (GET or POST)
141 - * @param string $api_url Complete API URL
142 - * @param array $body Request body data (for POST requests)
143 - * @param array $extra_headers Additional headers beyond the standard ones
144 - * @param int $timeout Request timeout in seconds (default: 30)
145 - * @return array|WP_Error Response array or WP_Error on failure
146 - */
147 - private static function make_api_request($method, $api_url, $body = [], $extra_headers = [], $timeout = 30) {
148 - $api_key = Options::get_instance()->get('api_key');
149 -
150 - $headers = [
151 - 'Authorization' => 'Bearer ' . $api_key,
152 - 'x-templately-ip' => self::get_ip(),
153 - 'x-templately-url' => home_url('/'),
154 - 'x-templately-version' => defined( 'TEMPLATELY_VERSION' ) ? constant( 'TEMPLATELY_VERSION' ) : '1.0.0',
155 - // Force JSON responses so the cloud returns JSON errors instead of an HTML
156 - // error page (which json_decode() cannot parse). Binary/XML downloads
157 - // (zip pack, attachment WXR) use their own wp_remote_* calls and bypass
158 - // this helper, so they are unaffected. Callers can override via $extra_headers.
159 - 'Accept' => 'application/json',
160 - ];
161 -
162 - // Add Content-Type for POST requests
163 - if (strtoupper($method) === 'POST') {
164 - $headers['Content-Type'] = 'application/json';
165 - }
166 -
167 - // Resolve requested platform: $_REQUEST wins (frontend-supplied), then caller's extra_headers, then default.
168 - if ( isset( $_REQUEST['requested_platform'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
169 - $extra_headers['x-templately-requested-platform'] = sanitize_text_field( wp_unslash( $_REQUEST['requested_platform'] ) );
170 - } elseif ( ! isset( $extra_headers['x-templately-requested-platform'] ) ) {
171 - $extra_headers['x-templately-requested-platform'] = 'templately';
172 - }
173 -
174 - // Merge additional headers
175 - $headers = array_merge($headers, $extra_headers);
176 -
177 - $args = [
178 - 'timeout' => $timeout,
179 - 'headers' => $headers,
180 - ];
181 -
182 - // Apply filter to allow network admin or other functionality to modify request args
183 - $args = apply_filters( 'templately_api_request_params', $args, $method, $api_url );
184 -
185 - // Add body for POST requests
186 - if (strtoupper($method) === 'POST') {
187 - $args['body'] = is_array($body) ? json_encode($body) : $body;
188 - }
189 -
190 - // Make the appropriate request
191 - if (strtoupper($method) === 'POST') {
192 - $response = wp_remote_post($api_url, $args);
193 - } else {
194 - $response = wp_remote_get($api_url, $args);
195 - }
196 -
197 - // Check for verification header in the response
198 - self::check_verification_header($response);
199 -
200 -
201 - // Check for site disconnection in response body
202 - self::check_site_disconnection($response);
203 -
204 - return $response;
205 - }
206 -
207 - /**
208 - * Make a GET request to Templately API
209 - *
210 - * @param string $endpoint API endpoint path (e.g., 'v2/import/pack/123')
211 - * @param array $query_params Query parameters as key-value pairs
212 - * @param array $extra_headers Additional headers beyond the standard ones
213 - * @param int $timeout Request timeout in seconds (default: 30)
214 - * @return array|WP_Error Response array or WP_Error on failure
215 - */
216 - public static function make_api_get_request($endpoint, $query_params = [], $extra_headers = [], $timeout = 30) {
217 - $api_url = self::get_api_url($endpoint);
218 -
219 - // Add query parameters if provided
220 - if (!empty($query_params)) {
221 - $api_url = add_query_arg($query_params, $api_url);
222 - }
223 -
224 - return self::make_api_request('GET', $api_url, [], $extra_headers, $timeout);
225 - }
226 -
227 - /**
228 - * Make a POST request to Templately API
229 - *
230 - * @param string $endpoint API endpoint path (e.g., 'v2/feedback/store')
231 - * @param array $body Request body data
232 - * @param array $extra_headers Additional headers beyond the standard ones
233 - * @param int $timeout Request timeout in seconds (default: 30)
234 - * @return array|WP_Error Response array or WP_Error on failure
235 - */
236 - public static function make_api_post_request($endpoint, $body = [], $extra_headers = [], $timeout = 30) {
237 - $api_url = self::get_api_url($endpoint);
238 - return self::make_api_request('POST', $api_url, $body, $extra_headers, $timeout);
239 - }
240 -
241 - /**
242 80 * Sanitize Helper
243 81 *
244 82 * @param mixed $value
245 83 * @param string $type
@@ -245,15 +83,15 @@
245 83 * @param string $type
246 84 *
247 85 * @return bool|string
248 86 */
249 - public static function sanitize($value, $type = 'text') {
250 - switch ($type) {
87 + public static function sanitize( $value, $type = 'text' ){
88 + switch ( $type ) {
251 89 case 'boolean':
252 - $sanitized_value = rest_sanitize_boolean($value);
90 + $sanitized_value = rest_sanitize_boolean( $value );
253 91 break;
254 92 default:
255 - $sanitized_value = sanitize_text_field($value);
93 + $sanitized_value = sanitize_text_field( $value );
256 94 break;
257 95 }
258 96
259 97 return $sanitized_value;
@@ -259,194 +97,8 @@
259 97 return $sanitized_value;
260 98 }
261 99
262 100 /**
263 - * Escape a string for safe embedding inside a GraphQL or JSON string literal.
264 - *
265 - * GraphQL string escaping rules are identical to JSON string escaping (per the
266 - * GraphQL spec), so wp_json_encode() is the authoritative escaper. We strip the
267 - * outer quotes it adds and return only the escaped inner content, ready to be
268 - * wrapped in your own quote pair.
269 - *
270 - * Handles pre-encoded JSON: when the caller has already run json_encode() +
271 - * wp_slash() on a value (e.g. categories, dependencies in Items.php), the
272 - * quotes are already escaped as \" and the string is ready to embed. Calling
273 - * wp_json_encode() again would double-escape those backslashes. We detect this
274 - * case by checking whether wp_unslash() produces valid JSON, and if so, return
275 - * the value directly without further encoding.
276 - *
277 - * @param string $value Raw string or wp_slash(json_encode()) output.
278 - * @return string Escaped string, safe to place between double quotes in GraphQL/JSON.
279 - */
280 - public static function esc_json_string( $value ) {
281 - $value = (string) $value;
282 -
283 - // If wp_slash() was applied to a JSON string upstream, the quotes are
284 - // already escaped (e.g. {\"key\":\"val\"}). Detect this by unslashing and
285 - // checking for valid JSON — if it matches, the value is already suitable
286 - // for embedding in a string literal; return it as-is to avoid doubling backslashes.
287 - $unslashed = wp_unslash( $value );
288 - if ( $unslashed !== $value ) {
289 - $decoded = json_decode( $unslashed, true );
290 - if ( json_last_error() === JSON_ERROR_NONE && null !== $decoded ) {
291 - return $value;
292 - }
293 - }
294 -
295 - $encoded = wp_json_encode( $value );
296 - // wp_json_encode wraps the value in "...", strip those outer quotes.
297 - return substr( $encoded, 1, -1 );
298 - }
299 -
300 - /**
301 - * Check for X-Templately-Verified header and update user verification status
302 - *
303 - * @param array|WP_Error $response The HTTP response array from wp_remote_get/wp_remote_post
304 - * @return void
305 - */
306 - public static function check_verification_header($response) {
307 - // Only process if response is not a WP_Error and contains headers
308 - if (is_wp_error($response)) {
309 - return;
310 - }
311 -
312 - // Retrieve the X-Templately-Verified header
313 - $verification_header = wp_remote_retrieve_header($response, 'X-Templately-Verified');
314 -
315 - // Check if header exists and has a truthy value
316 - if (!empty($verification_header) && filter_var($verification_header, FILTER_VALIDATE_BOOLEAN)) {
317 - try {
318 - // Get current user data
319 - $options = Options::get_instance();
320 - $user = $options->get('user');
321 -
322 - // Only update if user data exists and is not already verified
323 - if (!empty($user) && is_array($user) && empty($user['is_verified'])) {
324 - // Set verification flag
325 - $user['is_verified'] = true;
326 -
327 - // Save updated user data
328 - $options->set('user', $user);
329 -
330 - }
331 -
332 - if (!empty($user['is_verified'])){
333 - if(!headers_sent()){
334 - header( 'X-Templately-Verified: true' );
335 - if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
336 - self::log('User verification status already updated via X-Templately-Verified header');
337 - }
338 - }
339 -
340 - return true;
341 - }
342 - } catch (\Exception $e) {
343 - // Log error if debug logging is enabled
344 - if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
345 - self::log('Error updating user verification status: ' . $e->getMessage());
346 - }
347 - }
348 - }
349 -
350 - return false;
351 - }
352 -
353 - /**
354 - * Check for site disconnection status in API response body
355 - *
356 - * Detects SiteNotConnected errors and updates user disconnection status.
357 - * Sends X-Templately-Disconnected header for frontend detection.
358 - *
359 - *
360 - * @param array|WP_Error|mixed $response The response object or body array
361 - * @return bool True if site is disconnected, false otherwise
362 - */
363 - public static function check_site_disconnection($response) {
364 - if (is_wp_error($response)) {
365 - return false;
366 - }
367 -
368 - $response_body = $response;
369 -
370 - // If it's a raw WP response array with body, decode it
371 - if (is_array($response) && isset($response['body']) && is_string($response['body'])) {
372 - $response_body = json_decode(wp_remote_retrieve_body($response), true);
373 - }
374 -
375 - // Check if response body indicates site disconnection
376 - if (!is_array($response_body)) {
377 - return false;
378 - }
379 -
380 - $status = $response_body['status'] ?? null;
381 - $status_text = $response_body['statusText'] ?? null;
382 -
383 - // Check for SiteNotConnected error
384 - if ($status === 'error' && $status_text === 'SiteNotConnected') {
385 - try {
386 - // Get current user data
387 - $options = Options::get_instance();
388 - $user = $options->get('user');
389 -
390 - // Only update if user data exists
391 - if (!empty($user) && is_array($user)) {
392 - // Set disconnection flag
393 - $user['is_disconnected'] = true;
394 -
395 - // Save updated user data
396 - $options->set('user', $user);
397 -
398 - if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
399 - self::log('Site disconnection detected: SiteNotConnected status');
400 - }
401 - }
402 -
403 - // Send header for frontend detection
404 - if (!headers_sent()) {
405 - header('X-Templately-Disconnected: true');
406 - }
407 -
408 - return true;
409 - } catch (\Exception $e) {
410 - // Log error if debug logging is enabled
411 - if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
412 - self::log('Error updating site disconnection status: ' . $e->getMessage());
413 - }
414 - }
415 - }
416 -
417 - return false;
418 - }
419 -
420 - /**
421 - * Clear site disconnection status
422 - *
423 - * Called after successful site migration to reset the disconnection flag.
424 - *
425 - * @return void
426 - */
427 - public static function clear_site_disconnection() {
428 - try {
429 - $options = Options::get_instance();
430 - $user = $options->get('user');
431 -
432 - if (!empty($user) && is_array($user)) {
433 - $user['site_url'] = base64_encode( home_url('/') );
434 - $user['is_disconnected'] = false;
435 - $options->set('user', $user);
436 -
437 - if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
438 - self::log('Site disconnection status cleared and URL updated.');
439 - }
440 - }
441 - } catch (\Exception $e) {
442 - if (defined('TEMPLATELY_DEBUG_LOG') && constant('TEMPLATELY_DEBUG_LOG')) {
443 - self::log('Error clearing site disconnection status: ' . $e->getMessage());
444 - }
445 - }
446 - }
447 -
448 - /**
449 101 * API Error Formatter
450 102 *
451 103 * @param int $error_code
452 104 * @param mixed $error_message
@@ -454,18 +106,15 @@
454 106 * @param integer $status
455 107 * @param array $additional_data
456 108 * @return WP_Error
457 109 */
458 - public static function error($error_code, $error_message, $endpoint = '', $status = 500, $additional_data = []) {
110 + public static function error( $error_code, $error_message, $endpoint = '', $status = 500, $additional_data = [] ) {
459 111 $additional_data['status'] = $status;
460 - if (! empty($endpoint)) {
112 + if ( ! empty( $endpoint ) ) {
461 113 $additional_data['endpoint'] = $endpoint;
462 114 }
463 - // Add browser padding to avoid browsers not serving small JSON responses
464 - $padding_length = 512;
465 - $additional_data['browser_padding'] = str_repeat(' ', $padding_length);
466 115
467 - return new WP_Error($error_code, $error_message, $additional_data);
116 + return new WP_Error( $error_code, $error_message, $additional_data );
468 117 }
469 118
470 119 /**
471 120 * API Response Formatter
@@ -472,10 +121,10 @@
472 121 *
473 122 * @param mixed $data
474 123 * @return WP_REST_Response
475 124 */
476 - public static function success($data) {
477 - return new WP_REST_Response($data, 200);
125 + public static function success( $data ) {
126 + return new WP_REST_Response( $data, 200 );
478 127 }
479 128
480 129 /**
481 130 * Normalize Favourites Data
@@ -485,42 +134,42 @@
485 134 * @param boolean $undo
486 135 *
487 136 * @return array
488 137 */
489 - public function normalizeFavourites($favourites, $_favourites = [], $undo = false) {
490 - if ($undo) {
491 - $_favourites[$favourites['type']] = array_values(array_filter($_favourites[$favourites['type']], function ($item) use ($favourites) {
138 + public function normalizeFavourites( $favourites, $_favourites = [], $undo = false ){
139 + if( $undo ) {
140 + $_favourites[ $favourites['type'] ] = array_values(array_filter( $_favourites[ $favourites['type'] ], function( $item ) use( $favourites ) {
492 141 return $item != $favourites['id'];
493 - }));
142 + } ));
494 143 return $_favourites;
495 144 }
496 145
497 - array_map(function ($item) use (&$_favourites) {
498 - if (! is_null($item)) {
146 + array_map( function( $item ) use ( &$_favourites) {
147 + if( ! is_null( $item ) ) {
499 148 $item = (array) $item;
500 - if (isset($_favourites[$item['type']])) {
501 - $_favourites[$item['type']][] = $item['id'];
149 + if ( isset( $_favourites[ $item['type'] ] ) ){
150 + $_favourites[ $item['type'] ][] = $item['id'];
502 151 } else {
503 - $_favourites[$item['type']] = [$item['id']];
152 + $_favourites[ $item['type'] ] = [ $item['id'] ];
504 153 }
505 154 }
506 155 return $_favourites;
507 - }, $favourites);
156 + }, $favourites );
508 157
509 158 return $_favourites;
510 159 }
511 160
512 - public function normalizeReviews($favourites, $_favourites = [], $undo = false) {
513 - array_map(function ($item) use (&$_favourites) {
514 - if (! is_null($item)) {
161 + public function normalizeReviews( $favourites, $_favourites = [], $undo = false ){
162 + array_map( function( $item ) use ( &$_favourites) {
163 + if( ! is_null( $item ) ) {
515 164 $item = (array) $item;
516 - if (!isset($_favourites[$item['type']])) {
517 - $_favourites[$item['type']] = [];
165 + if ( !isset( $_favourites[ $item['type'] ] ) ){
166 + $_favourites[ $item['type'] ] = [];
518 167 }
519 - $_favourites[$item['type']][$item['type_id']] = $item['rating'];
168 + $_favourites[ $item['type'] ][$item['type_id']] = $item['rating'];
520 169 }
521 170 return $_favourites;
522 - }, $favourites);
171 + }, $favourites );
523 172
524 173 return $_favourites;
525 174 }
526 175
@@ -529,10 +178,10 @@
529 178 *
530 179 * @param object $triggered_by
531 180 * @return void
532 181 */
533 - public static function trigger_error($triggered_by, $method = 'get_instance') {
534 - $class = get_class($triggered_by);
182 + public static function trigger_error( $triggered_by, $method = 'get_instance' ){
183 + $class = get_class( $triggered_by );
535 184 $trace = debug_backtrace(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
536 185 $file = $trace[0]['file'];
537 186 $line = $trace[0]['line'];
538 187 trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
@@ -540,61 +189,23 @@
540 189
541 190 /**
542 191 * Printing Error Logs in debug.log file.
543 192 *
544 - * @param mixed $log The data to log
545 - * @param string $context Optional context for categorizing log entries
546 - * @param string $level Optional log level (debug, info, warning, error)
193 + * @param mixed $log
547 194 * @return void
548 195 */
549 - public static function log($log, $context = '', $level = 'info') {
550 - // Allow complete override of logging behavior
551 - $override_result = apply_filters('templately_log_override', null, $log, $context, $level);
552 - if ($override_result !== null) {
553 - return;
196 + public static function log( $log ){
197 + if ( defined('WP_DEBUG_LOG') && WP_DEBUG_LOG ) {
198 + if ( is_array( $log ) || is_object( $log ) ) {
199 + error_log( print_r( $log, true ) );
200 + } else {
201 + error_log( $log ?: '' );
202 + }
554 203 }
555 -
556 - // Only log if WP_DEBUG_LOG is enabled
557 - if (!defined('WP_DEBUG_LOG') || !WP_DEBUG_LOG) {
558 - return;
559 - }
560 -
561 - // Format the log message
562 - $formatted_message = self::format_log_message($log, $context, $level);
563 -
564 - // Write to error log
565 - error_log($formatted_message);
566 204 }
567 205
568 - /**
569 - * Format log message with context and level
570 - *
571 - * @param mixed $log The data to log
572 - * @param string $context Context for categorizing log entries
573 - * @param string $level Log level
574 - * @return string Formatted log message
575 - */
576 - private static function format_log_message($log, $context = '', $level = 'info') {
577 - // Convert arrays and objects to readable format
578 - if (is_array($log) || is_object($log)) {
579 - $log_content = print_r($log, true);
580 - } else {
581 - $log_content = (string) ($log ?: '');
582 - }
583 -
584 - // Build the formatted message
585 - $timestamp = current_time('Y-m-d H:i:s');
586 - $level_upper = strtoupper($level);
587 -
588 - if (!empty($context)) {
589 - return "[{$timestamp}] [{$level_upper}] [{$context}] {$log_content}";
590 - } else {
591 - return "[{$timestamp}] [{$level_upper}] {$log_content}";
592 - }
593 - }
594 -
595 - public static function should_flush() {
596 - if (isset($_REQUEST['is_lightspeed']) && $_REQUEST['is_lightspeed'] === 'true') {
206 + public static function should_flush(){
207 + if(isset($_GET['is_lightspeed']) && $_GET['is_lightspeed'] === 'true'){
597 208 return false;
598 209 }
599 210 return (!defined('TEMPLATELY_IGNORE_FLUSH_ALL') || !TEMPLATELY_IGNORE_FLUSH_ALL) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') === false;
600 211 }
@@ -604,9 +215,9 @@
604 215
605 216 while (!empty($queue)) {
606 217 $current_block = array_shift($queue);
607 218
608 - if ($search === $current_block['blockName']) {
219 + if($search === $current_block['blockName']){
609 220 return $current_block;
610 221 }
611 222
612 223 if (isset($current_block['innerBlocks'])) {
@@ -628,13 +239,13 @@
628 239 public static function current_user_can($cap, ...$args) {
629 240 $user = wp_get_current_user();
630 241
631 242 // Multisite super admin has all caps by definition, Unless specifically denied.
632 - if (is_multisite() && is_super_admin($user->ID)) {
243 + if ( is_multisite() && is_super_admin( $user->ID ) ) {
633 244 return true;
634 245 }
635 246
636 - $caps = map_meta_cap($cap, $user->ID, ...$args);
247 + $caps = map_meta_cap( $cap, $user->ID, ...$args );
637 248
638 249 switch ($cap) {
639 250 case 'install_plugins':
640 251 case 'upload_plugins':
@@ -654,24 +265,24 @@
654 265 break;
655 266 }
656 267
657 268 // Maintain BC for the argument passed to the "user_has_cap" filter.
658 - $args = array_merge(array($cap, $user->ID), $args);
269 + $args = array_merge( array( $cap, $user->ID ), $args );
659 270
660 271 /**
661 272 * See WP_User::has_cap() for description.
662 273 */
663 - $capabilities = apply_filters('user_has_cap', $user->allcaps, $caps, $args, $user);
274 + $capabilities = apply_filters( 'user_has_cap', $user->allcaps, $caps, $args, $user );
664 275
665 276 // Everyone is allowed to exist.
666 277 $capabilities['exist'] = true;
667 278
668 279 // Nobody is allowed to do things they are not allowed to do.
669 - unset($capabilities['do_not_allow']);
280 + unset( $capabilities['do_not_allow'] );
670 281
671 282 // Must have ALL requested caps.
672 - foreach ((array) $caps as $cap) {
673 - if (empty($capabilities[$cap])) {
283 + foreach ( (array) $caps as $cap ) {
284 + if ( empty( $capabilities[ $cap ] ) ) {
674 285 return false;
675 286 }
676 287 }
677 288
@@ -704,13 +315,13 @@
704 315 * Without this feature, some of the templates may not work properly.
705 316 *
706 317 * @return boolean
707 318 */
708 - public static function enable_elementor_container() {
709 - if (class_exists('Elementor\Plugin')) {
710 - $control_name = Plugin::instance()->experiments->get_feature_option_key('container');
711 - if (get_option($control_name) !== 'active') {
712 - update_option($control_name, 'active');
319 + public static function enable_elementor_container(){
320 + if(class_exists('Elementor\Plugin')) {
321 + $control_name = Plugin::instance()->experiments->get_feature_option_key( 'container' );
322 + if(get_option( $control_name ) === 'inactive') {
323 + update_option( $control_name, 'active' );
713 324 return true;
714 325 }
715 326 }
716 327 return false;
@@ -722,29 +333,17 @@
722 333 * @param [type] $args
723 334 * @param [type] $defaults
724 335 * @return array
725 336 */
726 - public static function recursive_wp_parse_args($args, $defaults) {
337 + public static function recursive_wp_parse_args( $args, $defaults ) {
727 338 $args = (array) $args;
728 339 $defaults = (array) $defaults;
729 340 $r = $defaults;
730 - foreach ($args as $key => $value) {
731 - if (is_array($value) && isset($r[$key])) {
732 - // also handle numeric array. if both $value and $r[ $key ] are numeric array. wp_is_numeric_array()
733 - if (wp_is_numeric_array($value) && wp_is_numeric_array($r[$key])) {
734 - foreach ($value as $k => $v) {
735 - if (!in_array($v, $r[$key])) {
736 - if (!isset($r[$key][$k])) {
737 - $r[$key][$k] = $v;
738 - } else {
739 - $r[$key][] = $v;
740 - }
741 - }
742 - }
743 - } else {
744 - $r[$key] = self::recursive_wp_parse_args($value, $r[$key]);
745 - }
746 - } else {
341 + foreach ( $args as $key => $value ) {
342 + if ( is_array( $value ) && isset( $r[ $key ] ) ) {
343 + $r[ $key ] = self::recursive_wp_parse_args( $value, $r[ $key ] );
344 + }
345 + else {
747 346 $r[$key] = $value;
748 347 }
749 348 }
750 349 return $r;
@@ -749,72 +348,5 @@
749 348 }
750 349 return $r;
751 350 }
752 351
753 - /**
754 - * Creates the plugin's working directory under wp-uploads and blocks direct
755 - * web access to it.
756 - *
757 - * Everything the importer needs on disk lands here: the extracted pack (its
758 - * WXR, its template JSON, its attachments), the AI-generated page JSON, and
759 - * the FSI logs. wp-uploads is web-served, so these paths are not private just
760 - * because their session id is a uuid — the guards are what makes them
761 - * unreadable, not the name.
762 - *
763 - * .htaccess covers Apache and is inherited by everything below this point;
764 - * web.config covers IIS; index.php stops a directory listing on any server.
765 - * nginx honours none of them, so an nginx site still needs a location rule —
766 - * this raises the floor, it does not replace server configuration.
767 - *
768 - * @param string $dir Absolute path to create and protect.
769 - *
770 - * @return bool Whether the directory exists and is usable.
771 - */
772 - public static function protect_directory( $dir ) {
773 - if ( empty( $dir ) ) {
774 - return false;
775 - }
776 -
777 - if ( ! is_dir( $dir ) && ! wp_mkdir_p( $dir ) ) {
778 - return false;
779 - }
780 -
781 - $guards = [
782 - 'index.php' => "<?php\n// Silence is golden.\n",
783 - '.htaccess' => "# Templately working files — not for direct access.\n<IfModule mod_authz_core.c>\n\tRequire all denied\n</IfModule>\n<IfModule !mod_authz_core.c>\n\tOrder allow,deny\n\tDeny from all\n</IfModule>\n",
784 - 'web.config' => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<system.webServer>\n\t\t<authorization>\n\t\t\t<deny users=\"*\" />\n\t\t</authorization>\n\t</system.webServer>\n</configuration>\n",
785 - ];
786 -
787 - foreach ( $guards as $file => $contents ) {
788 - $path = trailingslashit( $dir ) . $file;
789 - // Never overwrite: a site owner may have relaxed these deliberately.
790 - if ( ! file_exists( $path ) ) {
791 - @file_put_contents( $path, $contents ); // phpcs:ignore
792 - }
793 - }
794 -
795 - return true;
796 - }
797 -
798 - /**
799 - * Absolute path to the plugin's protected working directory in wp-uploads.
800 - *
801 - * @param string $sub Optional subdirectory ('tmp', 'log', 'preview', ...).
802 - *
803 - * @return string Trailing-slashed path, or '' when uploads is unusable.
804 - */
805 - public static function upload_dir( $sub = '' ) {
806 - $upload_dir = wp_upload_dir();
807 -
808 - if ( ! empty( $upload_dir['error'] ) || empty( $upload_dir['basedir'] ) ) {
809 - return '';
810 - }
811 -
812 - $base = trailingslashit( $upload_dir['basedir'] ) . 'templately' . DIRECTORY_SEPARATOR;
813 -
814 - // The guards go on the root so every subdirectory inherits them.
815 - self::protect_directory( $base );
816 -
817 - return '' === $sub ? $base : trailingslashit( $base . $sub );
818 - }
819 -
820 -}
352 +}