PluginProbe
Themify Builder / trunk
Themify Builder vtrunk
7.8.1 7.8.0 7.7.9 7.7.8 7.7.7 7.7.6 7.7.5 7.7.4 7.7.3 7.7.2 trunk 7.6.0 7.6.1 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.8 7.6.9 7.7.0 7.7.1
themify-builder / themify / class-themify-enqueue.php

class-themify-enqueue.php in Themify Builder trunk, at themify/class-themify-enqueue.php

2,458 lines 114.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH'))
3 exit; // Exit if accessed directly
4 /**
5 * The file that defines css/js loading class and concate css files
6 * @package Themify
7 */
8
9 class Themify_Enqueue_Assets {
10
11 public const THEMIFY_CSS_MODULES_URI=THEMIFY_URI . '/css/modules/';
12
13 private static $wc_shortcode_type = array();
14 private static $wc_data = array();
15 private static $css = array('mobile_concate' => array());
16 private static $done = array();
17 private static $localiztion = array();
18 private static $theme_css_support = array('mobile-menu'=>true,'rtl'=>true);
19 private static $concateFile = null;
20 private static $bufferLevel = 0;
21 private static $googleFonts = array();
22 private static $guttenbergCss = array();
23 public static $preLoadMedia = array();
24 public static $disableGoogleFontsLoad = null;
25 public static $isHeader = false;
26 public static $isFooter = false;
27 public static $mediaMaxWidth = 1200;
28 public static $mobileMenuActive = 1100;
29
30 public static $THEME_CSS_MODULES_URI = null;
31 public static $THEME_CSS_MODULES_DIR = null;
32 public static $THEME_WC_CSS_MODULES_DIR = null;
33 public static $THEME_WC_CSS_MODULES_URI = null;
34 public static $themeVersion = null;
35
36 public static function init() {
37 if (themify_is_themify_theme()) {
38 self::$THEME_CSS_MODULES_DIR = THEME_DIR . '/styles/modules/';
39 self::$THEME_CSS_MODULES_URI = THEME_URI . '/styles/modules/';
40
41 self::$THEME_WC_CSS_MODULES_DIR = THEME_DIR . '/styles/wc/modules/';
42 self::$THEME_WC_CSS_MODULES_URI = THEME_URI . '/styles/wc/modules/';
43
44 self::$themeVersion = wp_get_theme(get_template())->display('Version');
45 self::$mobileMenuActive = (int) themify_get('setting-mobile_menu_trigger_point', self::$mobileMenuActive, true);
46 }
47 if (!is_admin()) {
48 add_action('wp_body_open', array(__CLASS__, 'body_open'), 1);
49 add_filter('wp_default_scripts', array(__CLASS__, 'remove_default_js'));
50 add_action('wp', array(__CLASS__, 'lazy_init'), 1);
51 } else {
52 add_action('wp_loaded', array(__CLASS__, 'lazy_init'), 1);
53 add_action('admin_init', array(__CLASS__, 'loadMainScript'));
54 add_action('admin_footer', array(__CLASS__, 'js_localize'), 18);
55 }
56 add_filter('themify_loops_wrapper_class', array(__CLASS__, 'load_loop_css'), 100, 6);
57 add_filter('kses_allowed_protocols', array(__CLASS__, 'allow_lazy_protocols'), 100, 1);
58 add_filter('sgo_js_minify_exclude', array(__CLASS__,'exclude_main_js' ),1);
59 add_filter('sgo_javascript_combine_exclude', array( __CLASS__, 'exclude_main_js' ),1 );
60 add_filter('autoptimize_filter_js_exclude', array(__CLASS__,'exclude_main_js' ),1);
61 add_filter('autoptimize_filter_js_consider_minified',array(__CLASS__,'exclude_main_js' ),1);
62 add_filter('rocket_delay_js_exclusions', array( __CLASS__, 'exclude_main_js' ),1 );
63 add_filter('rocket_exclude_js',array( __CLASS__, 'exclude_main_js' ),1 );
64 add_filter( 'js_do_concat', [ __CLASS__, 'Automattic_page_optimize_js_exclude' ], 10, 2 );
65 add_action('pre_get_search_form', array(__CLASS__, 'load_search_form_css'), 9);
66 if (!is_admin() || themify_is_ajax()) {
67 add_filter('post_playlist', array(__CLASS__, 'wp_media_playlist'), 100, 3);
68 }
69 add_filter('cron_schedules', array(__CLASS__, 'cron_schedules'));
70 add_action('themify_cron_clear_css', array(__CLASS__, 'cron'));
71 if (!wp_next_scheduled('themify_cron_clear_css')) {
72 wp_schedule_event(time() + WEEK_IN_SECONDS * 4, 'four_week', 'themify_cron_clear_css');
73 }
74 }
75
76 public static function lazy_init() {
77 if (!is_admin() && !themify_is_login_page()) {
78 remove_action('wp_head', 'wp_resource_hints', 2);
79 if (self::$themeVersion !== null) {
80 add_action('wp_head', array(__CLASS__, 'header_meta'),-1111);
81 add_action('wp_head', array(__CLASS__, 'header_html'));
82 add_filter('wp_title', array(__CLASS__, 'wp_title'), 10, 2);
83 remove_action('wp_head', 'locale_stylesheet'); //remove rtl loading
84 }
85 add_action( 'template_redirect', array( __CLASS__, 'start_buffer' ), 1 );
86 add_action('wp_enqueue_scripts', array(__CLASS__, 'before_enqueue'), 7);
87 add_action('wp_enqueue_scripts', array(__CLASS__, 'after_enqueue'), 11);
88 add_filter('style_loader_tag', array(__CLASS__, 'style_header_tag'), 10, 4);
89 add_filter('render_block_data', array(__CLASS__, 'loadGuttenbergCss'), PHP_INT_MAX, 2);
90 add_action('wp_head', array(__CLASS__, 'css_position'),100);
91 add_action('wp_head', array(__CLASS__, 'wp_head'),-100);
92 add_action('wp_footer', array(__CLASS__, 'before_footer'), -1111);
93 add_action('wp_footer', array(__CLASS__, 'js_localize'), 18);
94 add_action('wp_footer', array(__CLASS__, 'wp_footer'), 100);
95 }
96 elseif(is_admin()){
97 add_action('admin_head', array(__CLASS__, 'dev_mode_styles'));
98 }
99 if(!is_admin() || themify_is_ajax()){
100 add_filter('widget_display_callback', array(__CLASS__, 'widget_css'), 100, 3);
101 add_action('wp_playlist_scripts',array(__CLASS__,'disable_playlist_template'),0,1);
102 }
103 add_filter('wp_audio_shortcode_library', array(__CLASS__, 'media_shortcode_library'), 100, 1);
104 add_filter('wp_video_shortcode_library', array(__CLASS__, 'media_shortcode_library'), 10, 1);
105 add_filter('wp_audio_shortcode', array(__CLASS__, 'audio_shortcode'), 100, 5);
106 add_filter('wp_video_shortcode_override', array(__CLASS__, 'video_shortcode'), 100, 4);
107 add_filter('embed_oembed_html',array(__CLASS__,'embed'),100,4);
108 if (themify_is_lazyloading()) {
109 themify_disable_other_lazy();
110 }
111
112 $cdn=' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com *.lottiefiles.com';
113 themify_set_headers(array(
114 'CONTENT-SECURITY-POLICY'=>array(
115 'img-src'=>'data:',
116 'style-src'=>"'unsafe-inline'".$cdn,
117 'style-src-elem'=>"'unsafe-inline'".$cdn,
118 'script-src'=>"'unsafe-inline' data:".$cdn,
119 'script-src-elem'=>"'unsafe-inline' data:".$cdn,
120 'connect-src'=>'https://themify.org *.lottiefiles.com',
121 'default-src'=>'https://themify.org data:'.$cdn
122 )
123 ));
124 }
125
126 public static function start_buffer(){
127 self::createDir();
128 ob_start(array(__CLASS__, 'getBuffer'));
129 self::$bufferLevel = ob_get_level();
130 }
131
132 public static function createDir():bool {
133 if (self::$concateFile === null) {
134 self::$concateFile = self::getCurrentVersionFolder();
135 if (!is_dir(self::$concateFile)) {
136 Themify_Filesystem::mkdir(self::$concateFile,true);
137 if (!Themify_Filesystem::is_dir(self::$concateFile)) {
138 clearstatcache();
139 Themify_Filesystem::mkdir(self::$concateFile,true);
140 if (!Themify_Filesystem::is_dir(self::$concateFile)) {
141 self::$concateFile = null;
142 return false;
143 }
144 }
145 }
146 }
147 return true;
148 }
149
150 public static function remove_default_js($scripts) {
151 if (!themify_builder_check('setting-jquery-migrate', 'performance-jquery_migrate') && !themify_is_login_page()) {
152 $script = $scripts->registered['jquery'];
153 if (!empty($script->deps)) { // Check whether the script has any dependencies
154 $key = 'jquery-migrate';
155 $index = isset($script->deps[1]) && $script->deps[1] === $key ? 1 : array_search($key, $script->deps, true);
156 if ($index !== false) {
157 unset($script->deps[$index]);
158 }
159 }
160 }
161 return $scripts;
162 }
163
164 public static function before_enqueue() {
165 self::add_css('tf_base', THEMIFY_URI . '/css/base.min.css', null, THEMIFY_VERSION);
166 if (self::$themeVersion !== null) {
167 self::add_css('themify_common', THEMIFY_URI . '/css/themify-common.css', null, THEMIFY_VERSION);
168 if(is_admin_bar_showing()){
169 self::add_css('themify_common_logged', THEMIFY_URI . '/css/themify-common-logged.css', null, THEMIFY_VERSION,'',true);
170 }
171 }
172 self::loadMainScript();
173 }
174
175 public static function after_enqueue() {
176 global $wp_styles, $wp_version;
177 $css = array('wp-block-library');
178 $is_theme = self::$themeVersion !== null;
179 if ($is_theme === true && themify_is_woocommerce_active()) {
180 add_filter('woocommerce_shortcode_products_query', array(__CLASS__, 'wc_shortcode_product'), 10, 3);
181 add_action('woocommerce_before_single_product_summary', array(__CLASS__, 'wc_shortcode_product_page'));
182 add_action('woocommerce_before_checkout_form_cart_notices', array(__CLASS__, 'wc_shortcode_checkout'));
183 add_action('woocommerce_account_content', array(__CLASS__, 'wc_shortcode_account'));
184 $wc_ver = WC()->version;
185 self::$localiztion['wc_version'] = $wc_ver;
186 wp_enqueue_script('wc-cart-fragments');//default load has been removed from wc 7.8.0
187 if (themify_is_shop() || is_product() || (!is_checkout() && !is_account_page() && !is_checkout_pay_page() && !is_edit_account_page() && !is_order_received_page() && !is_add_payment_method_page())) {
188 wp_enqueue_script('wc-add-to-cart-variation'); //load tmpl files
189 wp_enqueue_script('wc-single-product');
190 wp_enqueue_script(themify_wc_get_script_handle('wc-jquery-blockui'));
191 WC_Frontend_Scripts::localize_printed_scripts();
192 global $wp_scripts;
193
194 $js = array(themify_wc_get_script_handle('js-cookie'), 'wc-add-to-cart', 'wc-add-to-cart-variation', 'wc-cart-fragments', 'woocommerce', 'wc_additional_variation_images_script', 'wc-single-product');
195 $arr = array();
196 $disableOptimize = themify_check('setting-optimize-wc', true);
197 $isDefered=themify_check('setting-jquery', true)?true:($disableOptimize?false:!themify_check('setting-defer-wc', true));
198 foreach ($js as $v) {
199 if (isset($wp_scripts->registered[$v]) && wp_script_is($v)) {
200 if ($isDefered === true && !empty($wp_scripts->registered[$v]->extra['data'])) {
201 self::$wc_data[] = $wp_scripts->registered[$v]->extra['data'];
202 $wp_scripts->registered[$v]->extra['data']='';
203 }
204 if ($v === 'wc-single-product' && is_product()) {
205 continue;
206 }
207 if ($disableOptimize === false) {
208 $wp_scripts->done[] = $v;
209 }
210 $arr[$v] = $wp_scripts->registered[$v]->src;
211 if ($wc_ver !== $wp_scripts->registered[$v]->ver) {
212 $arr[$v] .= '?ver=' . $wp_scripts->registered[$v]->ver;
213 }
214 }
215 }
216 self::$localiztion['wc_js'] = $arr;
217 if ($disableOptimize === true) {
218 self::$localiztion['wc_js_normal'] = true;
219 }
220
221 // Localize photoswipe css
222 if (!empty($wp_styles->registered['photoswipe']->src)) {
223 wp_dequeue_style('photoswipe');
224 wp_dequeue_style('photoswipe-default-skin');
225 self::$localiztion['photoswipe'] = array('main' => $wp_styles->registered['photoswipe']->src, 'skin' => $wp_styles->registered['photoswipe-default-skin']->src);
226 }
227 $js = $arr = null;
228 }
229 $wc_block_prefix = 'wc-block';
230 if (intval($wc_ver[0]) >= 6) {
231 $wc_block_prefix .= 's';
232 }
233 $css[] = $wc_block_prefix . '-vendors-style';
234 $css[] = $wc_block_prefix . '-style';
235 $css[] = 'wp-block-library-theme';
236 $css[] = 'woocommerce-layout';
237 $css[] = 'woocommerce-smallscreen';
238 $css[] = 'woocommerce-general';
239 $css[] = 'select2';
240 $css[]='woocommerce-blocktheme';
241 $css[] = 'woocommerce_prettyPhoto_css';
242 }
243 $css = apply_filters('themify_deq_css', $css);
244 foreach ($css as $v) {
245 if (isset($wp_styles->registered[$v]) && wp_style_is($v)) {
246 $src = $wp_styles->registered[$v]->src;
247 if ($v === 'wp-block-library' || $v === 'wp-block-library-theme' || $v === $wc_block_prefix . '-style' || $v === $wc_block_prefix . '-vendors-style') {
248 if (empty($wp_styles->registered[$v]->deps) || ($v === $wc_block_prefix . '-style' && count($wp_styles->registered[$v]->deps) === 1 && $wp_styles->registered[$v]->deps[0] === $wc_block_prefix . '-vendors-style')) {
249 $wp_styles->done[] = $v;
250 self::$guttenbergCss[$v] = $src;
251 }
252 continue;
253 }
254 $wp_styles->done[] = $v;
255 $ver = $wp_styles->registered[$v]->ver;
256 if ($src[0] === '/' && $src[1] === '/') {
257 $src = (is_ssl() ? 'https:' : 'http:') . $src;
258 }
259 if (strpos($src, 'http') === false) {
260 $src = home_url($src);
261 }
262 if (empty($ver)) {
263 $ver = $wp_version;
264 }
265 wp_dequeue_style($v);
266 self::add_css($v, $src, $wp_styles->registered[$v]->deps, $ver, $wp_styles->registered[$v]->args);
267 }
268 }
269 $css = null;
270 if ($is_theme === true) {
271 if (isset(self::$theme_css_support['mobile-menu'])) {
272 self::addMobileMenuCss('mobile-menu', THEME_URI . '/mobile-menu.css');
273 }
274 if (function_exists('themify_theme_enqueue_header')) {
275 themify_theme_enqueue_header();
276 }
277 /* Disabel Guttenberg Global Style WP 5.9 */
278 // remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );
279 // wp_dequeue_style('global-styles');
280 }
281 }
282
283 public static function add_css(string $handle, string $src,?array $deps,?string $ver,?string $media = '',bool $in_footer = false) {
284 if (!isset(self::$css[$handle], self::$done[$src])) {
285 self::$done[$src] = true;
286 if (!$media) {
287 $media = 'all';
288 }
289 if (self::$concateFile === null || is_admin()) {
290 if (strpos($handle, 'http') !== false) {
291 $handle = crc32($handle);
292 }
293 self::$css[$handle] = array('s' => $src, 'v' => $ver);
294 if ($media !== 'all') {//need to get css files in ajax call(e.g builder live preview)
295 self::$css[$handle]['m'] = $media;
296 }
297 wp_enqueue_style($handle, $src, $deps, $ver, $media);
298 return;
299 }
300 if ($in_footer === true || self::$isFooter === true) {
301 if (!isset(self::$css['in_footer'])) {
302 self::$css['in_footer'] = array();
303 }
304 self::$css['in_footer'][$handle] = array('s' => $src, 'v' => $ver);
305 if ($media !== 'all') {
306 self::$css['in_footer'][$handle]['m'] = $media;
307 }
308 } else {
309 self::$css[$handle] = array('s' => $src, 'v' => $ver);
310 if ($media !== 'all') {
311 self::$css[$handle]['m'] = $media;
312 }
313 }
314 }
315 }
316
317 /**
318 * Deregister an stylesheet
319 *
320 * @param string $handle
321 * @param string $both
322 */
323 public static function remove_css(string $handle, string $type = 'both') {
324 if ($handle !== 'in_footer' && self::$css !== null) {
325 if ($type === 'both' || $type === 'main') {
326 unset(self::$css[$handle], self::$css['in_footer'][$handle]);
327 }
328 if ($type === 'both' || $type === 'mobile') {
329 unset(self::$css['mobile_concate'][$handle]);
330 }
331 }
332 }
333
334 public static function header_meta() {
335 ?>
336 <meta charset="<?php echo get_bloginfo('charset') ?>">
337 <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
338 <?php
339 }
340
341 public static function dev_mode_styles(){
342 if ( ( themify_is_dev_mode() || Themify_Maintenance_Mode::is_enabled() ) && is_admin_bar_showing() ){
343 if(is_admin()):
344 ?>
345 <style>
346 <?php endif;?>
347 /* admin bar dev mode */
348 #wpadminbar #wp-toolbar .tf_admin_bar_alert .ab-item{
349 padding-left:24px
350 }
351 .tf_admin_bar_alert>.ab-item:after{
352 content:'';
353 width:12px;
354 height:12px;
355 border-radius:100%;
356 background:#ff1212;
357 position:absolute;
358 top:50%;
359 left:6px;
360 transform:translateY(-50%);
361 animation:tf_bg 2s infinite alternate
362 }
363 #wpadminbar .tf_admin_bar_tooltip{
364 width:300px;
365 color:#ccc;
366 background-color:rgba(51,51,51,.9);
367 padding:10px 14px;
368 font-size:12px;
369 line-height:1.2em;
370 border-radius:8px;
371 margin-top:50px;
372 position:absolute;
373 display:none;
374 top:100%;
375 left:0;
376 box-sizing:border-box;
377 z-index:999999
378 }
379 #wpadminbar .tf_admin_bar_alert>.ab-item:hover .tf_admin_bar_tooltip{display:block}
380 @keyframes tf_bg{0%{background:#ffb800}100%{background:#ff1212}}
381 <?php if(is_admin()):?>
382 </style>
383 <?php
384 endif;
385 }
386 }
387
388 public static function wp_head() {
389 if (themify_is_lazyloading() === true) {
390 $blur = (int) themify_get('setting-lazy-blur', 25, true);
391 ?>
392 <style id="tf_lazy_style" data-no-optimize="1">
393 .tf_svg_lazy{
394 content-visibility:auto;
395 background-size:100% 25%!important;
396 background-repeat:no-repeat!important;
397 background-position:0 0, 0 33.4%,0 66.6%,0 100%!important;
398 transition:filter .3s linear!important;
399 <?php if ($blur > 0): ?>filter:blur(<?php echo $blur ?>px)!important;<?php endif; ?>
400 transform:translateZ(0)
401 }
402 .tf_svg_lazy_loaded{
403 filter:blur(0)!important
404 }
405 [data-lazy]:is(.module,.module_row:not(.tb_first)),.module[data-lazy] .ui,.module_row[data-lazy]:not(.tb_first):is(>.row_inner,.module_column[data-lazy],.module_subrow[data-lazy]){
406 background-image:none!important
407 }
408 </style>
409 <noscript>
410 <style>
411 .tf_svg_lazy{
412 display:none!important
413 }
414 </style>
415 </noscript>
416 <?php
417 }
418 ?>
419 <style id="tf_lazy_common" data-no-optimize="1">
420 <?php if (self::$themeVersion !== null): ?>
421 img{
422 max-width:100%;
423 height:auto
424 }
425 <?php endif; ?>
426 <?php self::dev_mode_styles()?>
427 :where(.tf_in_flx,.tf_flx){display:inline-flex;flex-wrap:wrap;place-items:center}
428 .tf_fa,:is(em,i) tf-lottie{display:inline-block;vertical-align:middle}:is(em,i) tf-lottie{width:1.5em;height:1.5em}.tf_fa{width:1em;height:1em;stroke-width:0;stroke:currentColor;overflow:visible;fill:currentColor;pointer-events:none;text-rendering:optimizeSpeed;buffered-rendering:static}#tf_svg symbol{overflow:visible}:where(.tf_lazy){position:relative;visibility:visible;display:block;opacity:.3}.wow .tf_lazy:not(.tf_swiper-slide){visibility:hidden;opacity:1}div.tf_audio_lazy audio{visibility:hidden;height:0;display:inline}.mejs-container{visibility:visible}.tf_iframe_lazy{transition:opacity .3s ease-in-out;min-height:10px}:where(.tf_flx),.tf_swiper-wrapper{display:flex}.tf_swiper-slide{flex-shrink:0;opacity:0;width:100%;height:100%}.tf_swiper-wrapper>br,.tf_lazy.tf_swiper-wrapper .tf_lazy:after,.tf_lazy.tf_swiper-wrapper .tf_lazy:before{display:none}.tf_lazy:after,.tf_lazy:before{content:'';display:inline-block;position:absolute;width:10px!important;height:10px!important;margin:0 3px;top:50%!important;inset-inline:auto 50%!important;border-radius:100%;background-color:currentColor;visibility:visible;animation:tf-hrz-loader infinite .75s cubic-bezier(.2,.68,.18,1.08)}.tf_lazy:after{width:6px!important;height:6px!important;inset-inline:50% auto!important;margin-top:3px;animation-delay:-.4s}@keyframes tf-hrz-loader{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(.1);opacity:.6}}.tf_lazy_lightbox{position:fixed;background:rgba(11,11,11,.8);color:#ccc;top:0;left:0;display:flex;align-items:center;justify-content:center;z-index:999}.tf_lazy_lightbox .tf_lazy:after,.tf_lazy_lightbox .tf_lazy:before{background:#fff}.tf_vd_lazy,tf-lottie{display:flex;flex-wrap:wrap}tf-lottie{aspect-ratio:1.777}.tf_w.tf_vd_lazy video{width:100%;height:auto;position:static;object-fit:cover}
429 </style>
430 <?php if (self::$themeVersion !== null){
431 themify_favicon_action();
432 }
433 self::$isHeader = true;
434 }
435
436 /**
437 * Outputs Header Code
438 *
439 * Hooked to "wp_head"[10], load after other scripts in the header
440 */
441 public static function header_html(){
442 echo themify_get('setting-header_html', '', true);
443 }
444
445 public static function css_position(){
446 echo '<!--tf_css_position-->';//bug in chrome https://bugs.chromium.org/p/chromium/issues/detail?id=332189x
447 }
448
449 public static function style_header_tag(string $tag, string $handle,string $href,string $media):string {
450 $src = strtok($href, '?');
451 unset(self::$preLoadMedia[$src]);
452 $preload = '<link rel="preload" href="' . $href . '" as="style"';
453 if ($media !== 'all' && $media) {
454 $preload .= ' media="' . $media . '"';
455 }
456 $preload .= '>' . $tag;
457 return $preload;
458 }
459
460 /**
461 * Set a default title for the front page
462 *
463 * @return string
464 * @since 1.7.6
465 */
466 public static function wp_title(string $title,string $sep):string {
467 if (empty($title) && ( is_home() || is_front_page() )) {
468 global $aioseop_options;
469 return !empty($aioseop_options) && class_exists('All_in_One_SEO_Pack',false) ? $aioseop_options['aiosp_home_title'] : get_bloginfo('name');
470 }
471 return str_replace($sep, '', $title);
472 }
473
474 public static function wc_shortcode_product($query_args, $attr, $type) {
475 if ($type === 'product') {
476 self::$wc_shortcode_type[$type] = true;
477 }
478 return $query_args;
479 }
480
481 public static function wc_shortcode_product_page() {
482 self::$wc_shortcode_type['product'] = true;
483 }
484
485 public static function wc_shortcode_checkout() {
486 self::$wc_shortcode_type['checkout'] = true;
487 }
488
489 public static function wc_shortcode_account($msg = '') {
490 self::$wc_shortcode_type['account'] = true;
491 return $msg;
492 }
493
494 public static function js_localize() {
495 global $wp_scripts;
496 if ( ! isset( $wp_scripts->registered['themify-main-script'] ) ) {
497 /* either something has gone horribly wrong, or the script is intentionally removed; bail. */
498 return;
499 }
500
501 self::localize_script('themify-main-script', 'themify_vars', apply_filters('themify_main_script_vars', self::$localiztion));
502 if(!is_admin()){
503 global $wp_scripts;
504 $inline_js=$wp_scripts->registered['themify-main-script']->extra['data'];
505 if(!empty(self::$wc_data)){
506 $inline_js.=implode('',self::$wc_data);
507 }
508 ?>
509 <!--googleoff:all-->
510 <!--noindex-->
511 <!--noptimize-->
512 <script id="tf_vars" data-no-optimize="1" data-noptimize="1" data-no-minify="1" data-cfasync="false" defer="defer" src="data:text/javascript;base64,<?php echo base64_encode($inline_js)?>"></script>
513 <!--/noptimize-->
514 <!--/noindex-->
515 <!--googleon:all-->
516 <?php
517 $wp_scripts->registered['themify-main-script']->extra['data'] = $inline_js=self::$wc_data=null;
518 do_action('tf_load_styles');
519 self::$isFooter = true;
520 }
521 else {
522 self::loadIcons();
523 }
524 self::$localiztion = array();
525 }
526
527 /**
528 * Copy of WP_Scripts::localize() except it uses JSON_UNESCAPED_SLASHES
529 *
530 * @documented in wp-includes/class.wp.scripts.php
531 */
532 public static function localize_script(string $handle,string $object_name,array $l10n) {
533 global $wp_scripts;
534
535 if ('jquery' === $handle) {
536 $handle = 'jquery-core';
537 }
538
539 if (is_array($l10n) && isset($l10n['l10n_print_after'])) { // back compat, preserve the code in 'l10n_print_after' if present.
540 $after = $l10n['l10n_print_after'];
541 unset($l10n['l10n_print_after']);
542 }
543
544 foreach ((array) $l10n as $key => $value) {
545 if (!is_scalar($value)) {
546 continue;
547 }
548
549 $l10n[$key] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8');
550 }
551
552 $script = "var $object_name = " . wp_json_encode($l10n, JSON_UNESCAPED_SLASHES) . ';';
553
554 if (!empty($after)) {
555 $script .= "\n$after;";
556 }
557
558 $data = $wp_scripts->get_data($handle, 'data');
559
560 if (!empty($data)) {
561 $script = "$data\n$script";
562 }
563
564 return $wp_scripts->add_data($handle, 'data', $script);
565 }
566
567 public static function before_footer() {
568 if (themify_is_woocommerce_active()) {
569 remove_action('wp_footer', 'wc_no_js');
570 }
571 if (self::$themeVersion !== null && !is_admin()) {
572 self::add_css('theme-style', THEME_URI . '/style.css', null, self::$themeVersion);
573 if (self::$mediaMaxWidth !== false) {
574 self::add_css('themify-media-queries', THEME_URI . '/media-queries.css', null, self::$themeVersion, '(max-width:' . self::$mediaMaxWidth . 'px)');
575 }
576 if (isset(self::$theme_css_support['wc'])) {
577 self::add_css('tf_theme_wc', THEME_URI . '/styles/wc/woocommerce.css', null, self::$themeVersion);
578 if (isset(self::$theme_css_support['wc_single_product']) && (isset(self::$wc_shortcode_type['product']) || is_product())) {
579 self::loadThemeWCStyleModule('single/product');
580 }
581 if ((isset(self::$theme_css_support['wc_account']) || isset(self::$theme_css_support['wc_register_form'])) && (isset(self::$wc_shortcode_type['account']) || is_account_page())) {
582 if (is_user_logged_in()) {
583 if(isset(self::$theme_css_support['wc_account'])){
584 self::loadThemeWCStyleModule('pages/account');
585 }
586 } elseif(isset(self::$theme_css_support['wc_register_form'])) {
587 self::loadThemeWCStyleModule('pages/register-form');
588 }
589 }
590 if (isset(self::$theme_css_support['wc_checkout']) && (isset(self::$wc_shortcode_type['checkout']) || is_checkout())) {
591 self::loadThemeWCStyleModule('pages/checkout');
592 }
593 if (isset(self::$theme_css_support['wc_cart']) && is_cart()) {
594 self::loadThemeWCStyleModule('pages/cart');
595 }
596 }
597 self::$wc_shortcode_type = null;
598 if (function_exists('themify_theme_enqueue_footer')) {
599 themify_theme_enqueue_footer();
600 }
601 if (is_rtl() && isset(self::$theme_css_support['rtl'])) {
602 self::add_css('theme-style-rtl', THEME_URI . '/rtl.css', null, self::$themeVersion);
603 }
604 themify_enqueue_framework_assets();
605 // Themify child base styling
606 if (is_child_theme()) {
607 $modified = filemtime(get_stylesheet_directory() . '/style.css');
608 if ($modified === false) {
609 $modified = '';
610 }
611 self::add_css('theme-style-child', get_stylesheet_uri(), null, self::$themeVersion . $modified);
612 }
613 // User stylesheet
614 $custom_css = get_template_directory() . '/custom_style.css';
615 if (is_file($custom_css)) {
616 $modified = filemtime($custom_css);
617 if ($modified === false) {
618 $modified = '';
619 }
620 self::add_css('custom-style', THEME_URI . '/custom_style.css', null, THEMIFY_VERSION . $modified);
621 }
622 unset($custom_css);
623 if (is_admin_bar_showing() && is_file(self::$THEME_CSS_MODULES_DIR . 'admin-bar.css')) {
624 self::loadThemeStyleModule('admin-bar', false, true);
625 }
626 if (class_exists('Themify_Builder',false) && Themify_Builder_Model::is_front_builder_activate() === true && is_file(self::$THEME_CSS_MODULES_DIR . 'builder-active.css')) {
627 self::loadThemeStyleModule('builder-active', false, true);
628 }
629 }
630 }
631
632 public static function wp_footer() {
633 if (!empty(self::$css['in_footer'])) {
634 foreach (self::$css['in_footer'] as $k => $v) {
635 $m = isset($v['m']) ? ' media="' . esc_attr( $v['m'] ) . '"' : '';
636 $href = esc_url( $v['s'] );
637 if (!empty($v['v'])) {
638 $href .= strpos($href, '?') === false ? '?' : '&';
639 $href .= 'ver=' . rawurlencode( $v['v'] );
640 }
641 ?>
642 <link rel="preload" href="<?php echo $href; ?>" as="style"<?php echo $m; ?>><link id="<?php echo esc_attr( $k ); ?>-css" rel="stylesheet" href="<?php echo $href; ?>"<?php echo $m; ?>>
643 <?php
644 }
645 }
646 if (self::$themeVersion !== null) {
647 echo "\n\n", themify_get('setting-footer_html', '', true);
648 }
649 add_action('shutdown',array(__CLASS__,'buffer_end'),PHP_INT_MAX);
650 }
651
652 public static function buffer_end():void{
653 while (ob_get_level() > self::$bufferLevel) {
654 ob_end_flush();
655 }
656
657 if (ob_get_level() === self::$bufferLevel) {
658 ob_end_flush();
659 }
660 }
661
662 private static function minify_concate_css_should_preserve_comment(string $inner):bool {
663 $inner = trim($inner);
664 if ($inner === '') {
665 return false;
666 }
667 if (preg_match('/^(.+\s+)?framework\s+[\w.+-]+$/i', $inner) === 1) {
668 return true;
669 }
670 if (preg_match('/\.css$/i', $inner) === 1) {
671 return true;
672 }
673 return false;
674 }
675
676 /**
677 * Strip block comments; leaves quoted strings unchanged (handles \\ escapes).
678 * Keeps theme/framework version and per-file path comments from getBuffer().
679 */
680 private static function minify_concate_css_strip_comments(string $css):string {
681 $len = strlen($css);
682 $out = '';
683 for ($i = 0; $i < $len; $i++) {
684 $c = $css[$i];
685 if ($c === '"' || $c === "'") {
686 $q = $c;
687 $out .= $q;
688 for ($i++; $i < $len; $i++) {
689 $c = $css[$i];
690 $out .= $c;
691 if ($c === '\\' && $i + 1 < $len) {
692 $out .= $css[++$i];
693 continue;
694 }
695 if ($c === $q) {
696 break;
697 }
698 }
699 continue;
700 }
701 if ($c === '/' && $i + 1 < $len && $css[$i + 1] === '*') {
702 $commentStart = $i;
703 $innerStart = $i + 2;
704 for ($i += 2; $i < $len; $i++) {
705 if ($css[$i] === '*' && $i + 1 < $len && $css[$i + 1] === '/') {
706 $inner = substr($css, $innerStart, $i - $innerStart);
707 if (self::minify_concate_css_should_preserve_comment($inner)) {
708 $out .= substr($css, $commentStart, $i - $commentStart + 2);
709 }
710 $i++;
711 break;
712 }
713 }
714 continue;
715 }
716 $out .= $c;
717 }
718 return $out;
719 }
720
721 /**
722 * Compress whitespace and braces/semicolons in concatenated cache CSS.
723 *
724 * Only normalizes whitespace runs to a single space, then trims around { } ; — we do not
725 * strip spaces around :, commas, +, ~, or >. That keeps transition/animation/background/
726 * grid-template shorthands, !important, and multi-token values intact.
727 *
728 * Avoids stripping around > (child combinator): the same character appears in @container
729 * (width > 700px), @supports selector(...), and arbitrary custom-property values.
730 *
731 * Native CSS nesting (&) is unchanged by comment removal; avoid adding combinator-only
732 * regex passes without tracking parens/at-rules if minification is extended later.
733 */
734 private static function minify_concate_css(string $css):string {
735 if ($css === '') {
736 return '';
737 }
738 if (strncmp($css, "\xEF\xBB\xBF", 3) === 0) {
739 $css = substr($css, 3);
740 }
741 $css = self::minify_concate_css_strip_comments($css);
742 if ($css === '') {
743 return '';
744 }
745 $quoted = array();
746 $css = preg_replace_callback(
747 '/"(?:\\\\.|[^\\\\"])*"|\'(?:\\\\.|[^\\\\\'])*\'/',
748 static function (array $m) use (&$quoted): string {
749 $quoted[] = $m[0];
750 return '##TFQ' . (count($quoted) - 1) . '##';
751 },
752 $css
753 );
754 if (!is_string($css)) {
755 return '';
756 }
757 $css = preg_replace('/\s+/', ' ', $css);
758 $css = preg_replace('/\s*{\s*/', '{', $css);
759 $css = preg_replace('/\s*;\s*/', ';', $css);
760 $css = preg_replace('/\s*}\s*/', '}', $css);
761 $css = trim($css);
762 for ($i = count($quoted) - 1; $i >= 0; $i--) {
763 $css = str_replace('##TFQ' . $i . '##', $quoted[$i], $css);
764 }
765 return $css;
766 }
767
768 private static function getBuffer(string $body):string{
769 $key = '';
770 $exist = $hasFonts = false;
771 self::$css = apply_filters('themify_main_concate', self::$css);
772 self::$css['mobile_concate'] = apply_filters('themify_mobile_concate', self::$css['mobile_concate']);
773 foreach (self::$css as $k => $v) {
774 if ($k !== 'in_footer' && $k !== 'mobile_concate') {
775 $key .= $k . $v['v'];
776 }
777 }
778 $output = '';
779 if ($key !== '') {
780 if (isset(self::$css['woocommerce-general']) && strpos($body, 'star-rating') !== false) {
781 self::addPreLoadMedia(dirname(self::$css['woocommerce-general']['s'],2) . '/fonts/star.woff', 'preload', 'font', null, null, 'high');
782 }
783 $isDevMode=themify_is_dev_mode() && (!class_exists('Themify_Builder_Model',false) || !Themify_Builder_Model::is_front_builder_activate());
784 $isConcateDisabled = themify_is_concate_disabled();
785 $regenerate = false;
786 if(self::$concateFile===null || $isConcateDisabled===true){
787 $isDevMode=true;
788 $exist=false;
789 $key='';
790 }
791 else{
792 $key .= implode('', array_keys(self::$css['mobile_concate']));
793 $key = crc32($key);
794 self::$concateFile .= 'themify-' . $key . '.css';
795 $exist = Themify_Filesystem::is_file(self::$concateFile);
796 if ($exist === true) {
797 $regenerate = !apply_filters('themify_concate_css', !$isDevMode, self::$concateFile); //opposite logic for backward compatibility
798 $isDeleted = Themify_Filesystem::is_file(self::$concateFile . 'del');
799 $regenerate = $regenerate === true || $isDeleted === true;
800 if ($regenerate === true) {
801 if ($isDeleted === true) {
802 Themify_Filesystem::delete(self::$concateFile . 'del','f');
803 }
804 $exist = false;
805 }
806 unset($isDeleted);
807 }
808 }
809 if ($exist === false) {
810 if (!isset($str)) {
811 $str = '';
812 }
813 // Add theme and fw version
814 $theme_name = '';
815 $replace = array(THEMIFY_URI, home_url());
816 if (self::$themeVersion !== null) {
817 $theme = wp_get_theme();
818 $theme_name = (is_child_theme() ? $theme->parent()->Name : $theme->display('Name')) . ' ' . self::$themeVersion . ' ';
819 $replace[] = THEME_URI;
820 $theme = null;
821 }
822 $str = PHP_EOL . '/* ' . $theme_name . 'framework ' . THEMIFY_VERSION . ' */' . $str . PHP_EOL;
823 $str = '@charset "UTF-8";' . $str;
824 unset($theme_name);
825 if(self::$themeVersion!==null && (self::$concateFile===null || $isConcateDisabled===true)){
826 $key='';
827 }
828 foreach (self::$css as $k => $v) {
829 if ($k !== 'in_footer' && $k !== 'mobile_concate') {
830 $content = $key !== ''? Themify_Filesystem::get_file_content($v['s']) : null;
831 if (!empty($content)) {
832 $dir = dirname($v['s']);
833 $content = strtr($content,
834 array(
835 '@charset "UTF-8";'=>'',
836 '..'=>dirname($dir),
837 "url('fonts/"=>"url({'$dir}/fonts/",
838 "url('images/"=>"url('{$dir}/images/",
839 "url(fonts/"=>"url({$dir}/fonts/",
840 "url(images/"=>"url({$dir}/images/"
841 ));
842 if ($k === 'woocommerce-general') {
843 $content = str_replace('@font-face{', '@font-face{font-display:swap;', $content);
844 }
845 if (isset($v['m'])) {
846 $content = '@media ' . $v['m'] . '{' . PHP_EOL . $content . PHP_EOL . '}';
847 }
848 $str .= PHP_EOL . '/*' . str_replace($replace, '', $v['s']) . '*/' . PHP_EOL . $content;
849 }
850 elseif (!Themify_Filesystem::get_file_content($v['s'], true)) {
851 $key = $str = '';
852 }
853 if (isset(self::$preLoadMedia[$k])) {
854 unset(self::$preLoadMedia[$k]);
855 }
856 $media = isset($v['m'])?' media="'.$v['m'].'"':'';
857 $output .= '<link rel="preload" href="' . $v['s'] . '?ver=' . $v['v'] . '" as="style"'.$media.'>' . "\n" . '<link id="' . $k . '-css" rel="stylesheet" href="' . $v['s'] . '?ver=' . $v['v'] . '"'.$media.'>' . "\n";
858 }
859 }
860 unset($content);
861 if (!empty(self::$css['mobile_concate'])) {
862 $media = 'screen and (max-width:' . self::$mobileMenuActive . 'px)';
863 $mobileStr = PHP_EOL . '/* START MOBILE MENU CSS */' . PHP_EOL . '@media ' . $media . '{';
864 foreach (self::$css['mobile_concate'] as $k => $v) {
865 $content = $key !== '' ? Themify_Filesystem::get_file_content($v) : null;
866 if (!empty($content)) {
867 $mobileStr .= PHP_EOL . '/*' . str_replace($replace, '', $v) . '*/' . PHP_EOL . trim($content);
868 } else {
869 $mobileStr = $key = '';
870 }
871 if (isset(self::$preLoadMedia[$k])) {
872 unset(self::$preLoadMedia[$k]);
873 }
874 $output .= '<link rel="preload" href="' . $v . '?ver=' . self::$themeVersion . '" media="' . $media . '" as="style"><link id="tf-mobile-' . $k . '-css" rel="stylesheet" href="' . $v . '?ver=' . self::$themeVersion . '" media="' . $media . '">';
875 }
876 unset(self::$css['mobile_concate'], $content);
877 if ($mobileStr !== '') {
878 $mobileStr .= PHP_EOL . '}' . PHP_EOL . '/* END MOBILE MENU CSS */';
879 $str .= $mobileStr;
880 unset($mobileStr);
881 }
882 }
883 if ($key !== '' && (empty(self::$concateFile) || (($regenerate === true || !Themify_Filesystem::is_file(self::$concateFile))))) {
884 if (apply_filters('themify_minify_concate_css', !$isDevMode)) {
885 $str = self::minify_concate_css($str);
886 }
887 if(!file_put_contents(self::$concateFile.'tmp', $str) || Themify_Filesystem::rename(self::$concateFile.'tmp',self::$concateFile)===false){//tmp file need because file_put_contents isn't atomic(another process can read not ready file),locking file(LOCK_EX) is slow,that is why we are using rename(it is atomic)
888 $key = '';
889 Themify_Filesystem::delete(self::$concateFile.'tmp','f');
890 }
891 }
892 unset($str, $replace);
893 }
894 }
895 if ( true === apply_filters( 'themify_enable_lazyload', true ) ) {
896 $body = themify_make_lazy($body);
897 }
898 $path = self::getPreLoad();
899 if (self::$disableGoogleFontsLoad === null) {
900 $path.= self::loadGoogleFonts();
901 }
902 if (!themify_is_amp() && !preg_match('/<html[^>]*\s(?:amp|âš¡)(?:=|[\s>])/i', $body)) {
903 if ($key !== '') {
904 $upload_dir = themify_upload_dir();
905 $href = str_replace($upload_dir['basedir'], $upload_dir['baseurl'], self::$concateFile);
906 unset($upload_dir);
907 $path .= '<link rel="preload" fetchpriority="high" href="' . $href . '" as="style"><link fetchpriority="high" id="themify_concate-css" rel="stylesheet" href="' . $href . '">';
908 } else {
909 $path .= $output;
910 // Placeholder for generate-style.js in dev mode; empty style tags invalidate AMP.
911 if ($output !== '' || themify_is_dev_mode()) {
912 $path .= '<style id="themify_concate-css"></style>';
913 }
914 }
915 }
916 unset($output);
917 self::$concateFile = null;
918 if (strpos($body, 'fonts.googleapis.com') !== false) {
919 $path .= '<link rel="dns-prefetch" href="https://fonts.gstatic.com">';
920 }
921 if (strpos($body, '//www.youtube.com/embed') !== false) {
922 $path .= '<link rel="preconnect" href="https://www.youtube.com">';
923 }
924 if (strpos($body, '//player.vimeo.com/video') !== false) {
925 $path .= '<link rel="preconnect" href="https://player.vimeo.com">';
926 }
927 if (themify_get('setting-ga_m_id', '', true) !== '' || strpos($body, 'googletagmanager.com') !== false) {
928 $path .= '<link rel="preconnect" href="https://www.google-analytics.com">';
929 }
930 if ( class_exists( 'TF_SV_Framework', false ) ) {
931 $path .= TF_SV_Framework::get_frontend_head_fragment();
932 }
933 if (self::$themeVersion !== null && ($custom_css = themify_get('setting-custom_css', false, true))) {
934 $path.='<!--custom css:start--><style>'. $custom_css.'</style><!--custom css:end-->';
935 }
936 self::$css = self::$googleFonts = self::$preLoadMedia = $rep=array();
937 if(strpos($body,'<!--tf_svg_holder-->')!==false){
938 $rep['<!--tf_svg_holder-->']=self::loadIcons(false);
939 }
940 else{
941 $rep['</body>']=self::loadIcons(false).'</body>';
942 }
943 if(strpos($body,'<!--tf_css_position-->')!==false){
944 $rep['<!--tf_css_position-->']=$path;
945 }
946 else{
947 $rep['</head>']=$path.'</head>';
948 }
949 return strtr($body,$rep);
950 }
951
952 public static function loadIcons(bool $echo = true) {
953 $fonts = Themify_Icon_Font::get_used_icons();
954 $svg = '<svg id="tf_svg" style="display:none"><defs>';
955 if (!empty($fonts)) {
956 $st = '';
957 foreach ($fonts as $k => $v) {
958 if ( $v === false ) {
959 continue;
960 }
961 $w = isset($v['vw']) ? $v['vw'] : '32';
962 $h = isset($v['vh']) ? $v['vh'] : '32';
963 $p = isset($v['is_fontello']) ? ' transform="matrix(1 0 0 -1 0 ' . $h . ')"' : '';
964 $svg .= '<symbol id="tf-' . $k . '" viewBox="0 0 ' . $w . ' ' . $h . '"><path d="' . $v['p'] . '"' . $p . '/></symbol>';
965 if (isset($v['w'])) {
966 $st .= '.tf_fa.tf-' . $k . '{width:' . $v['w'] . 'em}';
967 }
968 }
969 if ($st !== '') {
970 $svg .= '<style id="tf_fonts_style">' . $st . '</style>';
971 $st = null;
972 }
973 }
974 $svg .= '</defs></svg>';
975 $fonts = null;
976 if ($echo === false) {
977 return $svg;
978 }
979 echo $svg;
980 }
981
982 private static function get_webp_support():string {
983 return PHP_EOL . '#BEGIN_WEBP_OUTPUT_BY_THEMIFY
984 <IfModule mod_rewrite.c>
985 RewriteEngine On
986 # serves a .webp image instead of jpg/png
987 RewriteCond %{HTTP_ACCEPT} image/webp
988 RewriteCond %{REQUEST_FILENAME} ^(.+)\.(jpe?g|jpg|png|gif)$
989 RewriteCond %1\.webp -f
990 RewriteRule ^(.+)\.(jpe?g|jpg|png|gif)$ $1.webp [T=image/webp,E=accept:1]
991 </IfModule>
992 <IfModule mod_headers.c>
993 Header append Vary Accept env=REQUEST_image
994 </IfModule>
995 <IfModule mod_mime.c>
996 AddType image/webp .webp
997 </IfModule>
998 #END_WEBP_OUTPUT_BY_THEMIFY
999 ' . PHP_EOL;
1000 }
1001
1002 private static function get_gzip_htaccess():string {
1003 return PHP_EOL . '#BEGIN_GZIP_OUTPUT_BY_THEMIFY
1004 <IfModule mod_rewrite.c>
1005 <Files *.js.gz>
1006 AddType "text/javascript" .gz
1007 AddEncoding gzip .gz
1008 </Files>
1009 <Files *.css.gz>
1010 AddType "text/css" .gz
1011 AddEncoding gzip .gz
1012 </Files>
1013 <Files *.svg.gz>
1014 AddType "image/svg+xml" .gz
1015 AddEncoding gzip .gz
1016 </Files>
1017 <Files *.json.gz>
1018 AddType "application/json" .gz
1019 AddEncoding gzip .gz
1020 </Files>
1021 # Serve pre-compressed gzip assets
1022 RewriteCond %{HTTP:Accept-Encoding} gzip
1023 RewriteCond %{REQUEST_FILENAME}.gz -f
1024 RewriteRule ^(.*)$ $1.gz [QSA,L]
1025 </IfModule>
1026 #END_GZIP_OUTPUT_BY_THEMIFY
1027 ' . PHP_EOL;
1028 }
1029
1030 private static function get_mod_rewrite():string {
1031 return PHP_EOL . '#BEGIN_GZIP_COMPRESSION_BY_THEMIFY
1032 <IfModule mod_deflate.c>
1033 #add content typing
1034 AddType application/x-gzip .gz .tgz
1035 AddEncoding x-gzip .gz .tgz
1036 # Insert filters
1037 AddOutputFilterByType DEFLATE text/plain
1038 AddOutputFilterByType DEFLATE text/html
1039 AddOutputFilterByType DEFLATE text/xml
1040 AddOutputFilterByType DEFLATE text/css
1041 AddOutputFilterByType DEFLATE application/xml
1042 AddOutputFilterByType DEFLATE application/xhtml+xml
1043 AddOutputFilterByType DEFLATE application/rss+xml
1044 AddOutputFilterByType DEFLATE application/javascript
1045 AddOutputFilterByType DEFLATE application/x-javascript
1046 AddOutputFilterByType DEFLATE application/x-httpd-php
1047 AddOutputFilterByType DEFLATE application/x-httpd-fastphp
1048 AddOutputFilterByType DEFLATE image/svg+xml
1049 AddOutputFilterByType DEFLATE image/svg
1050 <IfModule mod_headers.c>
1051 # Make sure proxies don\'t deliver the wrong content
1052 Header append Vary User-Agent env=!dont-vary
1053 </IfModule>
1054 </IfModule>
1055 # END GZIP COMPRESSION
1056 ## EXPIRES CACHING ##
1057 <IfModule mod_expires.c>
1058 ExpiresActive On
1059 ExpiresByType image/jpg "access plus 1 year"
1060 ExpiresByType image/jpeg "access plus 1 year"
1061 ExpiresByType image/gif "access plus 1 year"
1062 ExpiresByType image/png "access plus 1 year"
1063 ExpiresByType image/webp "access plus 1 year"
1064 ExpiresByType image/apng "access plus 1 year"
1065 ExpiresByType image/svg+xml "access plus 1 year"
1066 ExpiresByType image/svg "access plus 1 year"
1067 ExpiresByType image/ico "access plus 1 year"
1068 ExpiresByType image/x-icon "access plus 1 year"
1069 ExpiresByType application/gzip "access plus 1 year"
1070 ExpiresByType text/css "access plus 1 year"
1071 ExpiresByType text/x-component "access plus 1 year"
1072 ExpiresByType text/javascript "access plus 1 year"
1073 ExpiresByType text/x-javascript "access plus 1 year"
1074 ExpiresByType application/pdf "access plus 1 month"
1075 ExpiresByType application/javascript "access plus 1 year"
1076 ExpiresByType application/x-javascript "access plus 1 year"
1077 ExpiresByType application/json "access plus 1 year"
1078 ExpiresByType application/ld+json "access plus 1 year"
1079 ExpiresByType application/xml "access plus 0 seconds"
1080 ExpiresByType text/xml "access plus 0 seconds"
1081 ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
1082 ExpiresByType text/cache-manifest "access plus 0 seconds"
1083 ExpiresByType audio/ogg "access plus 4 months"
1084 ExpiresByType audio/mp3 "access plus 4 months"
1085 ExpiresByType video/mp4 "access plus 4 months"
1086 ExpiresByType video/ogg "access plus 4 months"
1087 ExpiresByType video/webm "access plus 4 months"
1088 ExpiresByType application/atom+xml "access plus 1 day"
1089 ExpiresByType application/rss+xml "access plus 1 day"
1090 ExpiresByType application/font-woff "access plus 1 year"
1091 ExpiresByType application/vnd.ms-fontobject "access plus 1 year"
1092 ExpiresByType application/x-font-ttf "access plus 1 year"
1093 ExpiresByType font/opentype "access plus 1 year"
1094 ExpiresByType font/woff "access plus 1 year"
1095 ExpiresByType font/woff2 "access plus 1 year"
1096 ExpiresByType font/application/x-font-woff2 "access plus 1 year"
1097 ExpiresByType application/font-woff2 "access plus 1 year"
1098 </IfModule>
1099 #Alternative caching using Apache`s "mod_headers", if it`s installed.
1100 #Caching of common files - ENABLED
1101 <IfModule mod_headers.c>
1102 <FilesMatch "\.(pdf|xls|rar|zip|tgz|tar|html|txt)$">
1103 Header set Cache-Control "max-age=2628000, public"
1104 </FilesMatch>
1105 <FilesMatch "\.(jpg|jpeg|gif|png|webp|apng|svg|js|mjs|css|mp3|ogg|mpe?g|avi|gz|woff|woff2|eot|ttf|mp4|doc|ico|ogv|svgz|otf|rss|ppt|mid|midi|wav|bmp|rtf|json|jsonld)$">
1106 Header set Cache-Control "max-age=31536000, public"
1107 </FilesMatch>
1108 # Set Keep Alive Header
1109 Header set Connection keep-alive
1110 </IfModule>
1111
1112 <IfModule mod_gzip.c>
1113 mod_gzip_on Yes
1114 mod_gzip_dechunk Yes
1115 mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
1116 mod_gzip_item_include handler ^cgi-script$
1117 mod_gzip_item_include mime ^text/.*
1118 mod_gzip_item_include mime ^application/x-javascript.*
1119 mod_gzip_item_exclude mime ^image/.*
1120 mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
1121 </IfModule>
1122
1123 # If your server don`t support ETags deactivate with "None" (and remove header)
1124 <IfModule mod_expires.c>
1125 <IfModule mod_headers.c>
1126 Header unset ETag
1127 </IfModule>
1128 FileETag None
1129 </IfModule>
1130 ## EXPIRES CACHING ##
1131 #END_GZIP_COMPRESSION_BY_THEMIFY' . PHP_EOL;
1132 }
1133
1134 public static function rewrite_htaccess($gzip = false, $webp = false,$browser=false) {
1135 $htaccess_file = self::getHtaccessFile();
1136 if (is_file($htaccess_file) && Themify_Filesystem::is_writable($htaccess_file)) {
1137 if (themify_get_server() === 'iis') {//for iis we need to add webp mimeType
1138 $iis_config = get_home_path() . 'web.config';
1139 if (is_file($iis_config) && Themify_Filesystem::is_writable($iis_config)) {
1140 $rules = trim(Themify_Filesystem::get_contents($iis_config));
1141 if (!empty($rules) && strpos($rules, 'mimeType="image/webp"') === false) {
1142 $replace = '<!--BEGIN_WEBP_OUTPUT_BY_THEMIFY-->
1143 <mimeMap fileExtension=".webp" mimeType="image/webp"/>
1144 <!--END_WEBP_OUTPUT_BY_THEMIFY-->';
1145 if (preg_match_all('#\<staticContent\>#', $rules) > 0) {
1146 $rules = preg_replace('#\<staticContent\>#', '<staticContent>' . $replace, $rules, 1);
1147 } else {
1148 $rules = preg_replace('#\<rewrite\>#', '<staticContent>' . $replace . '</staticContent><rewrite>', $rules, 1);
1149 }
1150 unset($replace);
1151 Themify_Filesystem::put_contents($iis_config, trim($rules));
1152 }
1153 }
1154 unset($iis_config);
1155 }
1156 $rules = trim(Themify_Filesystem::get_contents($htaccess_file));
1157 $startOutputTag = '#BEGIN_GZIP_OUTPUT_BY_THEMIFY';
1158 $endOutputTag = '#END_GZIP_OUTPUT_BY_THEMIFY';
1159
1160 $startGzipTag = '#BEGIN_GZIP_COMPRESSION_BY_THEMIFY';
1161 $endGzipTag = '#END_GZIP_COMPRESSION_BY_THEMIFY';
1162
1163 $startWebTag = '#BEGIN_WEBP_OUTPUT_BY_THEMIFY';
1164 $endWebTag = '#END_WEBP_OUTPUT_BY_THEMIFY';
1165 $hasChange = false;
1166
1167 if ($webp === false) {
1168 if (strpos($rules, $startWebTag) === false) {
1169 $rules = self::get_webp_support() . $rules;
1170 $hasChange = true;
1171 }
1172 } elseif (strpos($rules, $startWebTag) !== false) {
1173 $startsAt = strpos($rules, $startWebTag);
1174 $endsAt = strpos($rules, $endWebTag, $startsAt);
1175 $textToDelete = substr($rules, $startsAt, ($endsAt + strlen($endWebTag)) - $startsAt);
1176 $rules = str_replace($textToDelete, '', $rules);
1177 $hasChange = true;
1178 }
1179
1180 if ($gzip === false) {
1181 if (strpos($rules, $startOutputTag) === false) {
1182 $rules = self::get_gzip_htaccess() . $rules;
1183 $hasChange = true;
1184 }
1185 }
1186 elseif (strpos($rules, $startOutputTag) !== false) {
1187 $startsAt = strpos($rules, $startOutputTag);
1188 $endsAt = strpos($rules, $endOutputTag, $startsAt);
1189 $textToDelete = substr($rules, $startsAt, ($endsAt + strlen($endOutputTag)) - $startsAt);
1190 $rules = str_replace($textToDelete, '', $rules);
1191 $hasChange = true;
1192 }
1193
1194 if($browser===false){
1195 if (strpos($rules, 'mod_deflate.c') === false && strpos($rules, 'mod_gzip.c') === false) {
1196 $rules .= self::get_mod_rewrite();
1197 $hasChange = true;
1198 }
1199 }
1200 elseif (strpos($rules, $startGzipTag) !== false) {
1201 $startsAt = strpos($rules, $startGzipTag);
1202 $endsAt = strpos($rules, $endGzipTag, $startsAt);
1203 $textToDelete = substr($rules, $startsAt, ($endsAt + strlen($endGzipTag)) - $startsAt);
1204 $rules = str_replace($textToDelete, '', $rules);
1205 $hasChange = true;
1206 }
1207
1208 if ($hasChange === true) {
1209 return Themify_Filesystem::put_contents($htaccess_file, trim($rules));
1210 }
1211 }
1212 }
1213
1214 public static function getHtaccessFile():string{
1215 $f=get_home_path() . '.htaccess';
1216 if(!is_file($f)){
1217 $f=ABSPATH . '.htaccess';
1218 }
1219 return $f;
1220 }
1221
1222 public static function addCssToFile(string $handle, string $src,?string $ver = THEMIFY_VERSION, $position = false):bool {
1223 if (self::$concateFile === null) {
1224 return false;
1225 }
1226 if (!isset(self::$css[$handle])) {
1227 if ($position === false) {
1228 self::$css[$handle] = array('s' => $src, 'v' => $ver);
1229 } elseif (isset(self::$css[$position])) {
1230 $keys = array_keys(self::$css);
1231 $index = array_search($position, $keys) + 1;
1232 self::$css = array_slice(self::$css, 0, $index) + array($handle => array('s' => $src, 'v' => $ver)) + array_slice(self::$css, $index);
1233 } else {
1234 return false;
1235 }
1236 }
1237 return true;
1238 }
1239
1240 public static function addPreLoadJs(string $src,string $ver = THEMIFY_VERSION, string $importance = 'low'):array {
1241 return self::addPreLoadMedia($src, 'preload', 'script', $ver, null, $importance);
1242 }
1243
1244 public static function addPrefetchJs(string $src, string $ver = THEMIFY_VERSION, string $importance = 'low'):array {
1245 return self::addPreLoadMedia($src, 'prefetch', 'script', $ver, null, $importance);
1246 }
1247
1248 public static function addPreLoadCss(string $src, string $ver = THEMIFY_VERSION, $m = 'all', string $importance = ''):array {
1249 return self::addPreLoadMedia($src, 'preload', 'style', $ver, $m, $importance);
1250 }
1251
1252 public static function addPrefetchCss(string $src,string $ver = THEMIFY_VERSION, $m = 'all', string $importance = ''):array {
1253 return self::addPreLoadMedia($src, 'prefetch', 'style', $ver, $m, $importance);
1254 }
1255
1256 public static function addPreLoadMedia(string $src, string $rel = 'preload', string $type = 'image', $ver = '', $m = 'all', string $importance = ''):array {
1257
1258 if(!isset(self::$done[$src]) && ($rel!=='prefetch' || !isset(self::$preLoadMedia[$src]))){
1259 self::$preLoadMedia[$src] = array('t' => $type, 'r' => $rel);
1260 if ($type !== 'image' && $type !== 'font') {
1261 if ($type === 'style') {
1262 self::$preLoadMedia[$src]['m'] = $m;
1263 }
1264 if ($ver !== '') {
1265 self::$preLoadMedia[$src]['v'] = $ver;
1266 }
1267 }
1268 elseif($type==='image' && $ver!=='' && $ver!==null && $m!=='' && $m!==null && $m!=='all'){//ver is srcset, m sizes for image
1269 self::$preLoadMedia[$src]['srcset'] = $ver;
1270 self::$preLoadMedia[$src]['sizes'] = $m;
1271 }
1272 if ($importance !== '') {
1273 self::$preLoadMedia[$src]['i'] = $importance;
1274 }
1275 }
1276 return array('s'=>$src,'v'=>isset(self::$preLoadMedia[$src]['v'])?self::$preLoadMedia[$src]['v']:null);
1277 }
1278
1279 public static function add_js($handle, $src, $deps, $ver, $in_footer = true) {
1280 wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);
1281 }
1282
1283 public static function getKnownJs():array {
1284 static $arr = null;
1285 if ($arr === null) {
1286 $arr = array();
1287 if (!is_admin()) {
1288 $isDefered = self::$themeVersion !== null
1289 ? (themify_check('setting-jquery', true) ? true : (themify_check('setting-optimize-wc', true) ? false : !themify_check('setting-defer-wc', true)))
1290 : !themify_builder_check('setting-defer-wc', 'defer-wc', true);
1291 if ($isDefered===true && themify_is_woocommerce_active()) {
1292 $arr = array('flexslider', 'wc-single-product', 'woocommerce', 'zoom', themify_wc_get_script_handle('js-cookie'), themify_wc_get_script_handle('wc-jquery-blockui'), 'jquery-cookie', 'jquery-payment', 'prettyPhoto', 'prettyPhoto-init', 'select2', 'selectWoo', 'wc-address-i18n', 'wc-add-payment-method', 'wc-cart', 'wc-cart-fragments', 'wc-checkout', 'wc-country-select', 'wc-credit-card-form', 'wc-add-to-cart', 'wc-add-to-cart-variation', 'wc-geolocation', 'wc-lost-password', 'wc-password-strength-meter', 'photoswipe', 'photoswipe-ui-default', 'wc-add-to-cart-composite');
1293 //Authorize.Net Gateway for WooCommerce
1294 if (function_exists('wc_authorize_net_cim')) {
1295 $arr[] = 'wc-authorize-net-cim';
1296 $arr[] = 'wc-authorize-net-apple-pay';
1297 $arr[] = 'wc-authorize-net-my-payment-methods';
1298 $arr[] = 'sv-wc-payment-gateway-payment-form-v5_8_1';
1299 $arr[] = 'sv-wc-payment-gateway-my-payment-methods-v5_8_1';
1300 $arr[] = 'sv-wc-jilt-prompt-customers';
1301 $arr[] = 'sv-wc-apple-pay-v5_8_1';
1302 }
1303 if (defined('WOOCOMMERCE_GATEWAY_EWAY_VERSION')) {//plugin eWAY WooCommerce gateway
1304 $arr[] = 'eway-credit-card-form';
1305 }
1306 }
1307 if (defined('WPCF7_PLUGIN')) {
1308 $arr[] = 'contact-form-7';
1309 }
1310 if (defined('SBI_PLUGIN_DIR')) {//plugin instagram feed
1311 $arr[] = 'sb_instagram_scripts';
1312 }
1313 if (defined('LP_PLUGIN_FILE')) {//plugin learnpress
1314 $arr[] = 'lp-global';
1315 $arr[] = 'global';
1316 $arr[] = 'learnpress';
1317 $arr[] = 'lp-plugins-all';
1318 $arr[] = 'learn-press-enroll';
1319 $arr[] = 'quiz';
1320 $arr[] = 'wp-utils';
1321 $arr[] = 'course';
1322 $arr[] = 'checkout';
1323 $arr[] = 'profile-user';
1324 $arr[] = 'become-a-teacher';
1325 $arr[] = 'jquery-caret';
1326 }
1327 }
1328 }
1329 return $arr;
1330 }
1331
1332 public static function removeWebp($dir = null) {
1333 if ($dir === null) {
1334 $dir = themify_upload_dir('basedir');
1335 if (!Themify_Filesystem::is_dir($dir) || !Themify_Filesystem::is_readable($dir)) {
1336 return array('error' => sprintf(__('The directory %s doesn`t exist or not readable', 'themify'), $dir));
1337 }
1338 }
1339 $arr = array('.png', '.jpg', '.jpeg','.gif');
1340 $files = scandir($dir,SCANDIR_SORT_NONE);
1341 foreach ($files as $value) {
1342 $path = realpath($dir . DIRECTORY_SEPARATOR . $value);
1343 if (!Themify_Filesystem::is_dir($path)) {
1344 if (pathinfo($path, PATHINFO_EXTENSION) === 'webp') {
1345 foreach ($arr as $v) {
1346 if (Themify_Filesystem::is_file(str_replace('.webp', $v, $path))) {
1347 Themify_Filesystem::delete($path,'f');
1348 break;
1349 }
1350 }
1351 }
1352 } elseif ($value !== '.' && $value !== '..') {
1353 self::removeWebp($path);
1354 }
1355 }
1356 }
1357 /**
1358 * Load assets required by Themify framework
1359 *
1360 * @since 1.1.2
1361 */
1362 public static function loadMainScript() {
1363 //Enqueue main js that will load others needed js
1364 global $wp_scripts, $wp_version;
1365 if (!isset($wp_scripts->registered['themify-main-script']) && empty($_GET['legacy-widget-preview'])) { /* disable in Block widget preview */
1366 $dependencies = [];
1367 // if ( themify_is_woocommerce_active() || ! defined( 'THEMIFY_NOJQUERY' ) ) {
1368 $dependencies[] = 'jquery';
1369 // }
1370 wp_enqueue_script('themify-main-script', THEMIFY_URI . '/js/main.js', $dependencies, THEMIFY_VERSION, true);
1371 $args = array(
1372 'breakpoints' => themify_get_breakpoints(),
1373 'wp' => $wp_version,
1374 'ajax_url' => admin_url('admin-ajax.php'),
1375 'nonce' => wp_create_nonce( 'tf_nonce' ),
1376 'map_key' => wp_strip_all_tags( themify_builder_get('setting-google_map_key', 'builder_settings_google_map_key') ?: '' ),
1377 'bing_map_key' =>wp_strip_all_tags( themify_builder_get('setting-bing_map_key', 'builder_settings_bing_map_key') ?: '' ),
1378 'azure_key' => wp_strip_all_tags( themify_builder_get('setting-azure_map_key', 'builder_settings_azure_map_key') ?: '' ),
1379 'osm_tile_url' => apply_filters( 'themify_builder_osm_tile_url', 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png' ),
1380 'osm_tile_attribution' => apply_filters( 'themify_builder_osm_tile_attribution', '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>' ),
1381 'menu_tooltips' => [],
1382 'plugin_url'=>rtrim(plugins_url(),'/'),
1383 'content_url'=>content_url(),
1384 'includes_url' => trailingslashit( includes_url() )
1385 );
1386
1387 if (!themify_is_lazyloading()) {
1388 $args['lz'] = 1;
1389 } else {
1390 $args['lazy_threshold'] = themify_get('setting-lazy-threshold', 300, true );
1391 }
1392 if (self::$themeVersion !== null) {
1393 $themeSrc = THEME_URI . '/js/themify-script.js';
1394 $args['theme_v'] = self::$themeVersion;
1395 if (!is_admin()) {
1396 self::addPrefetchJs($themeSrc, self::$themeVersion);
1397 }
1398 }
1399 if(is_admin()){
1400 $args['is_admin'] = 1;
1401 }
1402 else{
1403 $args['emailSub']=__('Check this out!', 'themify');
1404 $args['nop']=__('Check this out!', 'themify');
1405 $args['lightbox']=themify_lightbox_vars_init();
1406 if (is_user_logged_in()) {
1407 $args['pg_opt_updt'] = __('Update', 'themify');
1408 if (current_user_can('edit_posts')) {
1409 $args['lgi'] = __('Your uploaded image is too large (%w x %hpx). Please resize it below 1600px and re-upload it.', 'themify');
1410 }
1411 $post_type = get_post_type_object(get_post_type());
1412 $t = $post_type ? $post_type->labels->singular_name : __('Page', 'themify');
1413 $args['pg_opt_t'] = sprintf('%s %s', $t, __('Options', 'themify'));
1414 }
1415
1416 if (!empty($wp_scripts->registered['wp-embed'])) {
1417 $wp_scripts->done[] = 'wp-embed';
1418 }
1419 if (self::$themeVersion !== null) {
1420 global $wp_styles, $wp_filter;
1421 if (isset($wp_filter['wp_head'], $wp_filter['wp_head']->callbacks[7], $wp_filter['wp_head']->callbacks[7]['print_emoji_detection_script'])) {
1422 add_filter('wp_resource_hints', array(__CLASS__, 'remove_emoji_prefetch'), 100, 2);
1423 if (themify_check('setting-emoji', true)) {
1424 $src = apply_filters('script_loader_src', includes_url('js/wp-emoji-release.min.js'), 'concatemoji');
1425 if (!empty($src)) {
1426 ob_start();
1427 print_emoji_detection_script();
1428 self::$localiztion['wp_emoji'] = trim(str_replace(array('<script type="text/javascript">', '<script>', '</script>'), array('', ''), ob_get_clean()));
1429 }
1430 }
1431 else {
1432 remove_action('wp_print_styles', 'print_emoji_styles');
1433 }
1434 remove_action('wp_head', 'print_emoji_detection_script', 7);
1435 remove_filter('embed_head', 'print_emoji_detection_script');
1436 }
1437
1438 self::$localiztion['menu_point'] = self::$mobileMenuActive;
1439 if (is_singular() && comments_open() && get_option('thread_comments') == 1) {
1440 self::$localiztion['commentUrl'] = home_url($wp_scripts->registered['comment-reply']->src);
1441 $wp_scripts->done[] = 'comment-reply';
1442 }
1443 $wp_scripts->done[] = 'wp-playlist';
1444 }
1445 }
1446 self::$localiztion += $args;
1447 unset($args);
1448 if (!self::$localiztion['bing_map_key']) {
1449 unset(self::$localiztion['bing_map_key']);
1450 }
1451 if (!self::$localiztion['map_key']) {
1452 unset(self::$localiztion['map_key']);
1453 }
1454 }
1455 }
1456
1457
1458 public static function remove_emoji_prefetch(array $urls, string $relation_type):array {
1459 if ($relation_type === 'dns-prefetch') {
1460 remove_filter('wp_resource_hints', array(__CLASS__, 'remove_emoji_prefetch'), 100);
1461 foreach ($urls as $k => $v) {
1462 if (strpos('core/emoji/', $v) !== false) {
1463 unset($urls[$k]);
1464 break;
1465 }
1466 }
1467 }
1468 return $urls;
1469 }
1470
1471 public static function addLocalization($key, $val, $type = false, $object_val = true) {
1472 if (self::$localiztion !== null) {
1473 if (!isset(self::$localiztion[$key])) {
1474 if ($type === false) {
1475 self::$localiztion[$key] = $val;
1476 } else {
1477 self::$localiztion[$key] = array();
1478 if ($type === 'arr') {
1479 self::$localiztion[$key][] = $val;
1480 } else {
1481 self::$localiztion[$key][$val] = $object_val;
1482 }
1483 }
1484 } else {
1485 if ($type === false) {
1486 self::$localiztion[$key] = $val;
1487 } elseif ($type === 'arr') {
1488 self::$localiztion[$key][] = $val;
1489 } else {
1490 self::$localiztion[$key][$val] = $object_val;
1491 }
1492 }
1493 }
1494 }
1495
1496 public static function getLocalization():array {
1497 return self::$localiztion;
1498 }
1499
1500 public static function loadGalleryCss() {
1501 self::add_css('tf_wp_gallery', self::THEMIFY_CSS_MODULES_URI . 'gallery.min.css', null, THEMIFY_VERSION);
1502 }
1503
1504 public static function preFetchMasonry() {
1505 self::addPrefetchJs(THEMIFY_URI . '/js/modules/isotop.js');
1506 }
1507
1508 public static function loadFluidMasonryCss($in_footer = false) {
1509 if (!isset(self::$css['tf_fluid_masonry'])) {
1510 self::preFetchMasonry();
1511 self::add_css('tf_fluid_masonry', self::THEMIFY_CSS_MODULES_URI . 'fluid-masonry.css', null, THEMIFY_VERSION, null, $in_footer);
1512 self::addLocalization('done', 'tf_fluid_masonry', true);
1513 }
1514 }
1515
1516 public static function loadAutoTilesCss() {
1517 self::loadGridCss('auto_tiles');
1518 }
1519
1520 public static function loadinfiniteCss() {
1521 if (!isset(self::$css['tf_infinite'])) {
1522 self::add_css('tf_infinite', self::THEMIFY_CSS_MODULES_URI . 'infinite.css', null, THEMIFY_VERSION, null, true);
1523 self::addLocalization('done', 'tf_infinite', true);
1524 }
1525 }
1526
1527 public static function loadThemeStyleModule(string $file, $media = '',bool $in_footer = false) {
1528 self::add_css('tf_theme_' . str_replace('/', '_', $file), self::$THEME_CSS_MODULES_URI . $file . '.css', null, self::$themeVersion, $media, $in_footer);
1529 }
1530
1531 public static function loadThemeWCStyleModule(string $file, $media = '',bool $in_footer = false) {
1532 self::add_css('tf_theme_wc_' . str_replace('/', '_', $file), self::$THEME_WC_CSS_MODULES_URI . $file . '.css', null, self::$themeVersion, $media, $in_footer);
1533 }
1534
1535 public static function loadGridCss(string $grid, bool $in_footer = false) {
1536 if (!isset(self::$css['tf_grid_' . $grid]) && in_array($grid, array('list-post', 'grid2-thumb', 'grid2', 'grid3', 'grid4', 'grid5', 'grid6', 'list-large-image', 'list-thumb-image', 'auto_tiles'), true)) {
1537 if ($grid === 'auto_tiles') {
1538 self::addPrefetchJs(THEMIFY_URI . '/js/modules/auto-tiles.js');
1539 }
1540 self::add_css('tf_grid_' . $grid, THEMIFY_URI . '/css/grids/' . $grid . '.css', null, THEMIFY_VERSION, null, $in_footer);
1541 if (isset(self::$theme_css_support[$grid]) && self::$THEME_CSS_MODULES_DIR !== null) {
1542 self::add_css('tf_grid_theme_' . $grid, self::$THEME_CSS_MODULES_URI . 'grids/' . $grid . '.css', null, self::$themeVersion, null, $in_footer);
1543 self::addLocalization('done', 'tf_grid_theme_' . $grid, true);
1544 }
1545 self::addLocalization('done', 'tf_grid_' . $grid, true);
1546 }
1547 }
1548
1549 public static function loadGoogleFonts() {
1550 if (!defined('THEMIFY_GOOGLE_FONTS') || THEMIFY_GOOGLE_FONTS == true) {
1551 $fonts = apply_filters('themify_google_fonts', self::$googleFonts);
1552 $res = array();
1553 foreach ($fonts as $font) {
1554 if (!empty($font) && preg_match('/^\w/', $font)) {
1555 /* fix the delimiter with multiple weight variants, it should use `,` and not `:`
1556 reset the delimiter between font name and first variant */
1557 $font = preg_replace('/,/', ':', str_replace(':', ',', $font), 1);
1558 $key = explode(':', $font)[0];
1559 if (!isset($res[$key])) {
1560 $res[$key] = array();
1561 }
1562 if (strpos($font, ',') !== false || strpos($font, ':') !== false) {
1563 $font = str_replace(array($key . ':', $key), array('', ''), explode(',', $font));
1564 foreach ($font as $f) {
1565 $res[$key][] = $f;
1566 /* when loading either italic or non-italic variant, make sure other variant is loaded too */
1567 $res[$key][] = strpos( $f, 'i' ) !== false ? (int) $f : $f . 'i';
1568 }
1569 } else {
1570 $res[$key][] = '400';
1571 $res[$key][] = '400i';
1572 }
1573 }
1574 }
1575 if (!empty($res)) {
1576 $fonts = array();
1577 foreach ($res as $k => $v) {
1578 $fonts[] = $k . ':' . implode(',', array_keys( array_flip($v)));
1579 }
1580 $fonts = implode('%7C', $fonts);
1581 $path = '://fonts.googleapis.com/css?family=' . $fonts . '&display=swap';
1582 $_key=Themify_Storage::getHash($fonts);
1583 $css =Themify_Storage::get($_key,'tf_fg_css_');
1584 $isNew=false;
1585 unset($fonts,$res);
1586 if(!$css){
1587 $resp = function_exists('themify_safe_remote_get_with_ssl_fallback')
1588 ? themify_safe_remote_get_with_ssl_fallback( 'https' . $path, array(
1589 'httpversion' => '2',
1590 'timeout' => 10,
1591 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
1592 ) )
1593 : wp_remote_get( 'https' . $path, array(
1594 'sslverify' => false,
1595 'httpversion' => '2',
1596 'timeout' => 10,
1597 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
1598 ) );
1599 $css = wp_remote_retrieve_body($resp);
1600 /* validate response's content type */
1601 $content_type = wp_remote_retrieve_header( $resp, 'content-type' );
1602 if ( is_wp_error( $css ) || strpos( $content_type, 'text/css' ) === false ) {
1603 $css='';
1604 }
1605 $isNew=true;
1606 unset($resp);
1607 }
1608 if ($css && strpos($css,'fonts.gstatic')!==false) {
1609 $donwload=themify_builder_check('setting-gf','setting-gf');
1610 if($donwload){
1611 $gfFonts=array();
1612 $split=explode('@font-face',$css);
1613 $css='';
1614 $maximum=10;
1615 $i=0;
1616 require_once ABSPATH . 'wp-admin/includes/image.php';
1617 require_once ABSPATH . 'wp-admin/includes/file.php';
1618 require_once ABSPATH . 'wp-admin/includes/media.php';
1619 add_filter('wp_handle_sideload_overrides',array(__CLASS__,'sideload_overrides_google_fonts'),9999,1);
1620 foreach($split as $v){
1621 $v=trim($v);
1622 if($v!=='' && $v[0]==='{'){
1623 $v=explode(';', str_replace(array('{','}'),'',$v));
1624 $arr=array();
1625 foreach($v as $styles){
1626 $styles=trim($styles);
1627 if($styles!==''){
1628 $props=explode(':',str_replace('https:','',$styles));
1629 if(isset($props[0],$props[1])){
1630 $prop=trim($props[0]);
1631 $value=trim($props[1]);
1632 if($prop==='src'){
1633 $value=explode(' ',$value)[0];
1634 $value=trim(str_replace(array('url',')','('),'',trim($value)));
1635 }
1636 elseif($prop==='unicode-range'){
1637 $value=str_replace(' ', '', $value);
1638 }
1639 $arr[$prop]=$value;
1640 }
1641 elseif(isset($props[0])){
1642 $arr['subset']=trim($props[0]);
1643 }
1644 }
1645 }
1646 if(!empty($arr['src'])){
1647 if(strpos($arr['src'],'fonts.gstatic')!==false){
1648 $fkey=$arr['font-family'];
1649 if(isset($arr['font-style'])){
1650 $fkey.=$arr['font-style'];
1651 }
1652 if(isset($arr['font-weight'])){
1653 $fkey.=$arr['font-weight'];
1654 }
1655 if(isset($arr['unicode-range'])){
1656 $fkey.=$arr['unicode-range'];
1657 }
1658 $googleFontsUrl='https:'.$arr['src'];
1659 $slug=Themify_Storage::getHash($fkey);
1660 global $wpdb;
1661 $query = "SELECT ID FROM $wpdb->posts WHERE post_type='attachment' AND post_parent=0 AND %s LIMIT 1";
1662 $attachment=$wpdb->get_row(sprintf($query,'post_name="'.esc_sql($slug).'"'));
1663 if(empty($attachment)){
1664 $filename=basename($googleFontsUrl);
1665 $attachment=$wpdb->get_row( sprintf($query, 'guid LIKE "%'.esc_sql($filename).'"'));
1666 }
1667 $url=!empty($attachment)?wp_get_attachment_url($attachment->ID):false;
1668 if($url!==false && !is_file(get_attached_file($attachment->ID))){
1669 $url=false;
1670 wp_delete_attachment($attachment->ID,true);
1671 }
1672 unset($attachment);
1673 if($url===false && $i<$maximum && !Themify_Storage::get($slug)){
1674 Themify_Storage::set($slug,1,MINUTE_IN_SECONDS*2);//set a value to block others threads
1675 $tmp = download_url($googleFontsUrl,10,false );
1676
1677 if(!is_wp_error( $tmp )){
1678 $file = array(
1679 'size' => filesize($tmp),
1680 'name'=> $filename,
1681 'error'=>0,
1682 'tmp_name' => $tmp
1683 );
1684 $desc=array(trim(str_replace(array('"',"'"),'',$arr['font-family'])));
1685 if(!empty($arr['subset'])){
1686 $desc[]=trim(str_replace(array('/','*'),'',$arr['subset']));
1687 }
1688 $desc[]=$arr['font-style'];
1689 $desc[]=$arr['font-weight'];
1690 $attach_id=media_handle_sideload( $file, 0,$filename,array(
1691 'post_mime_type'=>'font/woff2',
1692 'post_content'=>'Google Font: '.implode('-',$desc),
1693 'post_name'=>$slug
1694 ) );
1695 if(!is_wp_error($attach_id)){
1696 $url=wp_get_attachment_url($attach_id);
1697 $gfFonts[$googleFontsUrl]=$url;
1698 }
1699 unset($desc,$file,$attach_id);
1700 }
1701 Themify_Storage::delete($slug);
1702 Themify_Filesystem::delete($tmp,'f');
1703 }
1704 elseif($url!==false){
1705 $gfFonts[$googleFontsUrl]=$url;
1706 }
1707 $arr['src']=$url===false?$googleFontsUrl:$url;
1708 }
1709 $css.='@font-face{';
1710 foreach($arr as $prop=>$vv){
1711 if($prop!=='subset'){
1712 if($prop==='src'){
1713 $vv='url('.$vv.') format("woff2")';
1714 }
1715 $css.=$prop.':'.$vv.';';
1716 }
1717 }
1718 $css.='}';
1719 }
1720 }
1721 }
1722 unset($split);
1723 remove_filter('wp_handle_sideload_overrides',array(__CLASS__,'sideload_overrides_google_fonts'),9999);
1724 }
1725 if(($isNew===true && !$donwload) || !empty($gfFonts)){
1726 if(!empty($gfFonts)){
1727 $tmp =Themify_Storage::get($_key,'tf_fg_css_');//maybe another thread has changed it
1728 if($tmp){
1729 $css=strtr($tmp,$gfFonts);
1730 }
1731 unset($gfFonts,$tmp);
1732 }
1733 if($css!==''){
1734 if($isNew===true){
1735 $css = str_replace(array("\r\n","\n","\r","\t"),'',$css);
1736 $css = preg_replace('!\s+!',' ',$css);
1737 $css = str_replace(array(' {',' }','{ ','; ',': ',', '),array('{','}','{',';',':',','),$css);
1738 $css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css);
1739 }
1740 $css=str_replace(array('font-style:normal;','font-weight:400;'),'',$css);
1741 Themify_Storage::set($_key, $css, MONTH_IN_SECONDS * 6,'tf_fg_css_');
1742 }
1743 else{
1744 Themify_Storage::delete($_key,'tf_fg_css_');
1745 }
1746 }
1747 }
1748 if(!$css){
1749 $path = ( is_ssl() ? 'https' : 'http' ) . $path;
1750 // Use font-display=optional to prevent FOUT: browser uses fallback font rather than
1751 // showing a flash if the font is not cached. Swap &display=swap for &display=optional.
1752 $path_optional = str_replace( '&display=swap', '&display=optional', $path );
1753 $preconnect = '<link rel="preconnect" href="https://fonts.googleapis.com">'
1754 . '<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>';
1755 $css = $preconnect
1756 . '<link rel="preload" fetchpriority="high" as="style" href="' . $path_optional . '">'
1757 . '<link fetchpriority="high" id="themify-google-fonts-css" rel="stylesheet" href="' . $path_optional . '">';
1758 }
1759 else{
1760 $css='<style id="tf_gf_fonts_style">'.$css.'</style>';
1761 }
1762 return $css;
1763 }
1764 }
1765 return null;
1766 }
1767
1768 public static function sideload_overrides_google_fonts(array $overrides):array{
1769 $overrides['test_size']=$overrides['test_type']=false;
1770 return $overrides;
1771 }
1772
1773 public static function addGoogleFont(array $fonts) {
1774 foreach ($fonts as $v) {
1775 if(!in_array($v,self::$googleFonts,true)){
1776 self::$googleFonts[] = $v;
1777 }
1778 }
1779 }
1780
1781 public static function addMobileMenuCss(string $handler, string $src) {
1782 if (!isset(self::$css['mobile_concate'][$handler]) && !isset(self::$done[$src])) {
1783 self::$done[$src] = true;
1784 self::$css['mobile_concate'][$handler] = $src;
1785 }
1786 }
1787
1788 public static function preLoadAnimtion(bool $only_css = false) {
1789 static $is = false;
1790 if ($is === false) {
1791 self::addPreLoadCss(self::THEMIFY_CSS_MODULES_URI . 'animate.min.css');
1792 if ($only_css === false) {
1793 $is = true;
1794 self::addPreLoadJs(THEMIFY_URI . '/js/modules/animate.js');
1795 }
1796 }
1797 }
1798
1799 public static function preLoadSwiperJs(string $type = 'prefetch',string $only = 'all') {
1800 $url = THEMIFY_URI . '/js/modules/themify-carousel.js';
1801 $sw_url = THEMIFY_URI . '/js/modules/swiper/swiper.min.js';
1802 $sw_css = self::THEMIFY_CSS_MODULES_URI . 'swiper/swiper.css';
1803 if ($type === 'prefetch') {
1804 if ($only === 'all' || $only === 'css') {
1805 self::addPrefetchCss($sw_css);
1806 }
1807 if ($only === 'all' || $only === 'js') {
1808 self::addPrefetchJs($url);
1809 self::addPrefetchJs($sw_url);
1810 }
1811 } else {
1812 if ($only === 'all' || $only === 'css') {
1813 self::addPreLoadCss($sw_css);
1814 }
1815 if ($only === 'all' || $only === 'js') {
1816 self::addPreLoadJs($url);
1817 self::addPreLoadJs($sw_url);
1818 }
1819 }
1820 }
1821
1822 public static function preFetchFixedHeaderJs(string $type = 'prefetch') {
1823 $url = THEMIFY_URI . '/js/modules/fixedheader.js';
1824 if ($type === 'prefetch') {
1825 self::addPrefetchJs($url);
1826 } else {
1827 self::addPreLoadJs($url);
1828 }
1829 }
1830
1831 public static function preFetchSideMenuJs(string $type = 'prefetch') {
1832 $url = THEMIFY_URI . '/js/modules/themify-sidemenu.js';
1833 if ($type === 'prefetch') {
1834 self::addPrefetchJs($url);
1835 } else {
1836 self::addPreLoadJs($url);
1837 }
1838 }
1839
1840 public static function preFetchAnimtion(bool $only_css = false) {
1841 static $is = false;
1842 if ($is === false) {
1843 self::addPrefetchCss(self::THEMIFY_CSS_MODULES_URI . 'animate.min.css');
1844 if ($only_css === false) {
1845 $is = true;
1846 self::addPrefetchJs(THEMIFY_URI . '/js/modules/animate.js');
1847 }
1848 }
1849 }
1850
1851 public static function clearConcateCss($blog_id = false) {
1852 $cache_type = $blog_id === 'all' && is_multisite()? 'all' : 'blog';
1853 $dir = self::getCurrentVersionFolder(($cache_type === 'all' ? false : $blog_id));
1854 clearstatcache();
1855 if ($cache_type === 'all') {
1856 $concate_dir = '/themify-concate/';
1857 $dir=dirname(str_replace($concate_dir, '', $dir));
1858 if(strpos($dir,'/blogs.dir/')!==false){
1859 $dir=dirname($dir);
1860 $concate_dir='/files'.$concate_dir;
1861 }
1862 $dir = rtrim($dir, '/') . '/';
1863 if (Themify_Filesystem::is_dir($dir) && ($handle = opendir($dir))) {
1864 set_time_limit(0);
1865 while (false !== ($f = readdir($handle))) {
1866 if ($f !== '.' && $f !== '..') {
1867 $f = $dir . $f . $concate_dir;
1868 if (Themify_Filesystem::is_dir($f)) {
1869 self::markAsDeleteCssFile($f);
1870 }
1871 }
1872 }
1873 closedir($handle);
1874 }
1875 } else {
1876 self::markAsDeleteCssFile($dir);
1877 }
1878 TFCache::remove_cache($cache_type, false, $blog_id);
1879 TFCache::clear_3rd_plugins_cache();
1880 }
1881
1882 private static function markAsDeleteCssFile(string $dir) {
1883 if (is_dir($dir) && ($handle = opendir($dir))) {
1884 $dir = rtrim($dir, '/') . '/';
1885 while (false !== ($f = readdir($handle))) {
1886 if ($f !== '.' && $f !== '..') {
1887 if (is_dir($dir . $f)) {
1888 self::markAsDeleteCssFile($dir . $f);
1889 } else {
1890 $ext = pathinfo($f, PATHINFO_EXTENSION);
1891 $f = $dir . $f . 'del';
1892 if ($ext !== 'cssdel' && strpos($ext, 'cssdel') === false && !Themify_Filesystem::is_file($f)) {
1893 $fd = fopen($f, 'w');
1894 fclose($fd);
1895 }
1896 }
1897 }
1898 }
1899 closedir($handle);
1900 }
1901 }
1902
1903 public static function wp_media_playlist(string $html,array $attr, $instance):string {
1904 if (!isset($attr['type']) || $attr['type'] === 'audio') {
1905 return self::audio_playlist($attr);
1906 }
1907 if($attr['type']==='video' && themify_is_ajax()){
1908 remove_filter('post_playlist', array(__CLASS__, 'wp_media_playlist'), 100);
1909 $html= themify_make_lazy(wp_playlist_shortcode($attr));
1910 add_filter('post_playlist', array(__CLASS__, 'wp_media_playlist'), 100,3);
1911 }
1912 return $html;
1913 }
1914
1915 public static function audio_playlist(array $attr):string {
1916
1917 $post = get_post();
1918 $atts = shortcode_atts(
1919 array(
1920 'order' => 'ASC',
1921 'orderby' => 'menu_order ID',
1922 'id' => $post ? $post->ID : 0,
1923 'include' => '',
1924 'exclude' => '',
1925 'tracklist' => true,
1926 'tracknumbers' => true,
1927 'images' => true,
1928 'artists' => true
1929 ),
1930 $attr,
1931 'playlist'
1932 );
1933 $atts['type'] = 'audio';
1934 unset($post);
1935 $showImages = !empty($atts['images']);
1936 if (empty($attr['tracks'])) {
1937 $id = (int) $atts['id'];
1938 $args = array(
1939 'post_status' => 'inherit',
1940 'post_type' => 'attachment',
1941 'post_mime_type' => $atts['type'],
1942 'order' => $atts['order'],
1943 'orderby' => $atts['orderby'],
1944 'no_found_rows' => true
1945 );
1946
1947 if (!empty($atts['include'])) {
1948 $args['include'] = $atts['include'];
1949 $_attachments = get_posts($args);
1950 $attachments = array();
1951 foreach ($_attachments as $val) {
1952 $attachments[$val->ID] = $val;
1953 }
1954 unset($_attachments);
1955 } else {
1956 $args['post_parent'] = $id;
1957 if (!empty($atts['exclude'])) {
1958 $args['exclude'] = $atts['exclude'];
1959 }
1960 $attachments = get_children($args);
1961 }
1962 unset($args);
1963 if (empty($attachments)) {
1964 return '<div></div>';
1965 }
1966
1967 if (is_feed()) {
1968 $output = "\n";
1969 foreach ($attachments as $att_id => $attachment) {
1970 $output .= wp_get_attachment_link($att_id) . "\n";
1971 }
1972 return $output;
1973 }
1974
1975 $tracks = array();
1976 $mime_types = wp_get_mime_types();
1977 $metaArr = array('artist', 'album', 'length_formatted');
1978 foreach ($attachments as $attachment) {
1979 $url = wp_get_attachment_url($attachment->ID);
1980 $ftype = wp_check_filetype($url, $mime_types);
1981 $track = array(
1982 'src' => trim($url),
1983 'type' => $ftype['type'],
1984 'title' => $attachment->post_title,
1985 'caption' => $attachment->post_excerpt
1986 );
1987 $meta = wp_get_attachment_metadata($attachment->ID);
1988 if (!empty($meta)) {
1989 $track['meta'] = array();
1990 foreach ($metaArr as $m) {
1991 if (!empty($meta[$m])) {
1992 $track['meta'][$m] = $meta[$m];
1993 }
1994 }
1995 }
1996 if ($showImages === true) {
1997 $thumb_id = get_post_thumbnail_id($attachment->ID);
1998 if (!empty($thumb_id)) {
1999 list( $src, $width, $height ) = wp_get_attachment_image_src($thumb_id, 'thumbnail');
2000 } else {
2001 $src = wp_mime_type_icon($attachment->ID);
2002 $width = 48;
2003 $height = 64;
2004 }
2005 $track['thumb'] = array('src' => $src, 'width' => $width, 'height' => $height);
2006 }
2007
2008 $tracks[] = $track;
2009 }
2010 $mime_types = $metaArr = $attachments = null;
2011 } else {
2012 $tracks = $attr['tracks'];
2013 }
2014 $data = array(
2015 'type' => 'audio',
2016 'tracklist' => $atts['tracklist'] ? 1 : 0,
2017 'tracknumbers' => $atts['tracknumbers'] ? 1 : 0,
2018 'images' => $showImages === true ? 1 : 0,
2019 'artists' => $atts['artists'] ? 1 : 0,
2020 'tracks' => $tracks
2021 );
2022 $autoplay = !empty($attr['autoplay']) ? ' data-autoplay="1"' : '';
2023 $loop = !empty($attr['loop']) ? ' data-loop' : '';
2024 $loop .= !empty($attr['muted']) ? ' muted' : '';
2025 $tracks = $atts = null;
2026 $output = '<div class="wp-audio-playlist">' . themify_make_lazy('<audio controls="controls" preload="none"' . $autoplay . $loop . '></audio>');
2027 $output .= '<script type="application/json" class="tf-playlist-script">' . wp_json_encode($data) . '</script></div>';
2028 return $output;
2029 }
2030
2031 public static function widget_css($instance, $thiz, $args) {
2032 $id = $thiz->id_base;
2033 if ($id) {
2034 if ($id === 'themify-most-commented') {
2035 $id = 'themify-feature-posts';
2036 }
2037 elseif ($id === 'themify-social-links') {
2038 self::add_css('tf_theme_social_links', self::THEMIFY_CSS_MODULES_URI . 'social-links.css', null, THEMIFY_VERSION);
2039 self::addLocalization('done', 'tf_theme_social_links', true);
2040 }
2041 if(isset(self::$theme_css_support['widget_'.$id])){
2042 $k = 'tf_theme_widget_' . str_replace('-', '_', $id);
2043 if (!isset(self::$css[$k])) {
2044 self::add_css($k, self::$THEME_CSS_MODULES_URI . 'widgets/' . $id . '.css', null, self::$themeVersion);
2045 self::addLocalization('done', $k, true);
2046 }
2047 }
2048 }
2049 return $instance;
2050 }
2051
2052 public static function allow_lazy_protocols(array $protocols):array {
2053 $protocols[] = 'data';
2054 return $protocols;
2055 }
2056
2057 public static function audio_shortcode(string $html, array $attr, $media, $post_id, $library):string {
2058 return $library === 'tf_lazy' ? themify_make_lazy($html) : $html;
2059 }
2060
2061 public static function embed(string $cached_html, $url, $attr, $post_id):string {
2062 return str_replace('data-secret','data-lazy data-secret',$cached_html);
2063 }
2064
2065 public static function disable_playlist_template($type){
2066 remove_action( 'wp_playlist_scripts', 'wp_playlist_scripts' );
2067 }
2068
2069 public static function video_shortcode(string $html,array $attr, string $content, $instance):string {
2070 if (apply_filters('wp_video_shortcode_library', 'mediaelement') === 'tf_lazy') {
2071 $html_atts = array(
2072 'preload' => 'none',
2073 'playsinline'=>1,
2074 'webkit-playsinline'=>1
2075 );
2076 if (!empty($attr['src'])) {
2077 $video_url = parse_url($attr['src']);
2078 if (isset($video_url['host']) && ($video_url['host'] === 'www.youtube.com' || $video_url['host'] === 'youtube.com' || $video_url['host'] === 'youtu.be' || $video_url['host'] === 'www.vimeo.com' || $video_url['host'] === 'vimeo.com' || $video_url['host'] === 'player.vimeo.com')) {
2079 return $html;
2080 }
2081 unset($video_url);
2082 $html_atts['src'] = esc_url($attr['src']);
2083 }
2084 if(!empty($attr['disable_lazy'])){
2085 $html_atts['data-skip'] = 1;
2086 }
2087 if (!empty($attr['id'])) {
2088 $html_atts['id'] = $attr['id'];
2089 }
2090 if (!empty($attr['loop'])) {
2091 $html_atts['loop'] = 1;
2092 }
2093 if (!empty($attr['autoplay'])) {
2094 $html_atts['data-autoplay'] = 1;
2095 }
2096 if (!empty($attr['class'])) {
2097 $cl = trim(str_replace('wp-video-shortcode', '', $attr['class']));
2098 if ($cl !== '') {
2099 $html_atts['class'] = $cl;
2100 }
2101 }
2102 if (!empty($attr['width'])) {
2103 $html_atts['width'] = $attr['width'];
2104 }
2105 if (!empty($attr['height'])) {
2106 $html_atts['height'] = $attr['height'];
2107 }
2108 if (!empty($attr['poster'])) {
2109 $html_atts['data-poster'] = esc_url($attr['poster']);
2110 }
2111 $muted = isset( $attr['muted'] ) ? wp_validate_boolean( $attr['muted'] ) : false;
2112 if ( $muted ) {
2113 $html_atts['muted'] = 1;
2114 }
2115 $source='';
2116 $default_types = wp_get_video_extensions();
2117 $default_types[] = 'mov';
2118 $mimes=array();
2119 foreach ( $default_types as $ext ) {
2120 if (isset($attr[$ext])) {
2121 if(empty($mimes)){
2122 $mimes = wp_get_mime_types();
2123 }
2124 if(!isset($html_atts['src']) || !isset($mimes[$ext])){
2125 $type=wp_check_filetype($attr[$ext], $mimes);
2126 }
2127 if (isset($mimes[$ext])) {
2128 $m = $mimes[$ext];
2129 }
2130 else {
2131 $m = isset($type['type'])?$type['type']:null;
2132 }
2133 if ($m) {
2134 $source .= sprintf('<source type="%s" src="%s"/>', $m, esc_url($attr[$ext]));
2135 }
2136 if (!isset($html_atts['src']) && isset($type['ext']) && strtolower( $type['ext'] ) === $ext ) {
2137 $html_atts['src'] = $attr[ $ext ];
2138 }
2139 }
2140 }
2141 if (!empty( $html_atts['src'] ) ) {
2142 unset($mimes,$default_types);
2143 if(!isset($html_atts['width']) || !isset($html_atts['height'])){
2144 /* find video by their media type attribute */
2145 $size=themify_get_video_size($html_atts['src']);
2146 if($size!==null){
2147 if(!isset($html_atts['width']) && $size['w']!==''){
2148 $html_atts['width'] = $size['w'];
2149 }
2150 if(!isset($html_atts['height'])&& $size['h']!==''){
2151 $html_atts['height'] = $size['h'];
2152 }
2153 }
2154 }
2155 if(isset($html_atts['width'],$html_atts['height']) && $html_atts['width']>0 && $html_atts['height']>0){
2156 $html_atts['style']='aspect-ratio:'.($html_atts['width']/$html_atts['height']);
2157 }
2158 $html = '<video ' . themify_get_element_attributes($html_atts) . '>'.$source. '</video>' . trim($content);
2159 }
2160 }
2161 return $html;
2162 }
2163
2164 public static function media_shortcode_library($library):string {
2165 return 'tf_lazy';
2166 }
2167
2168 public static function load_loop_css($class, $post_type, $layout, $type, $moduleArgs = array(), $slug = false) {
2169 global $themify;
2170 if (self::$themeVersion !== null) {//only in themify theme
2171 if (!empty($themify->post_layout_type) && $themify->post_layout_type !== 'default') {
2172 $class[] = $themify->post_layout_type;
2173 }
2174 if ($post_type === 'product' && themify_is_woocommerce_active() && $type !== 'builder') {
2175 global $woocommerce_loop;
2176 if ((isset($woocommerce_loop['name']) && in_array( $woocommerce_loop['name'], [ 'up-sells', 'cross-sells', 'related' ], true ) ) || wc_get_loop_prop('is_shortcode')) {
2177 $layout = (int) wc_get_loop_prop('columns');
2178 $index = array_search('columns-' . $layout, $class, true);
2179 if ($index !== false) {
2180 unset($class[$index]);
2181 }
2182 $index = array_search('masonry', $class, true);
2183 if ($index !== false) {
2184 unset($class[$index]);
2185 }
2186 $index = array_search('infinite', $class, true);
2187 if ($index !== false) {
2188 unset($class[$index]);
2189 }
2190 $index = array_search('no-gutter', $class, true);
2191 if ($index !== false) {
2192 unset($class[$index]);
2193 }
2194 $layout = $layout === 1 ? 'list-post' : 'grid' . $layout;
2195 }
2196 }
2197 }
2198 self::loadGridCss($layout);
2199 if (in_array('masonry', $class, true)) {
2200 if (!in_array($layout, array('slider', 'auto_tiles'), true) || (!empty($themify->post_filter) && $themify->post_filter !== 'no')) {
2201 $class[] = 'tf_rel';
2202 if (in_array('tf_fluid', $class, true)) {
2203 self::loadFluidMasonryCss();
2204 } else {
2205 self::preFetchMasonry();
2206 }
2207 } else {
2208 $index = array_search('masonry', $class, true);
2209 if ($index !== false) {
2210 unset($class[$index]);
2211 }
2212 }
2213 }
2214 $class[] = $layout;
2215 return array_keys( array_flip($class));
2216 }
2217
2218 public static function get_css():array {
2219 return self::$css;
2220 }
2221
2222 /**
2223 * Check if the file belongs to themify(plugin, FW, theme and etc.)
2224 *
2225 * return boolean
2226 */
2227 public static function is_themify_file(string $file, string $handler):bool {
2228 return strpos($file, 'maps.google.com') === false && (strpos($handler, 'themify') !== false || strpos($handler, 'builder-') === 0 || strpos($handler, 'tf-') === 0 || strpos($handler, 'tb_builder') === 0|| strpos($handler, 'tbp') === 0 || (defined('THEME_URI') && strpos($file, THEME_URI) !== false) || preg_match('/themify[\.\-][^\/]*\.js/', $file));// match "themify.*.js" or "themify-*.js"
2229 }
2230
2231 public static function loadGuttenbergCss($parsed_block, $source_block) {
2232 remove_filter('render_block_data', array(__CLASS__, 'loadGuttenbergCss'), PHP_INT_MAX);
2233 if (!empty(self::$guttenbergCss)) {
2234 global $wp_styles, $wp_version;
2235 foreach (self::$guttenbergCss as $k => $src) {
2236 if (isset($wp_styles->registered[$k])) {
2237 $ver = $wp_styles->registered[$k]->ver;
2238 if (empty($ver)) {
2239 $ver = $wp_version;
2240 }
2241 if (strpos($src, 'http') === false) {
2242 $src = get_site_url(null, $src);
2243 }
2244 self::add_css($k, $src, $wp_styles->registered[$k]->deps, $ver, $wp_styles->registered[$k]->args);
2245 }
2246 }
2247 self::$guttenbergCss = null;
2248 }
2249 return $parsed_block;
2250 }
2251
2252 public static function getCurrentVersionFolder($blog_id = false):string {
2253 global $wp_version;
2254 $object = wp_get_theme();
2255 $globalKey = THEMIFY_VERSION . $wp_version . $object->get('Name');
2256 $globalKey .= self::$themeVersion !== null ? self::$themeVersion : $object->get('Version');
2257 if (themify_is_woocommerce_active()) {
2258 if (defined('WC_VERSION')) {
2259 $globalKey .= WC_VERSION;
2260 } elseif (function_exists('WC')) {
2261 $wc = WC();
2262 if (is_object($wc) && !empty($wc->version)) {
2263 $globalKey .= $wc->version;
2264 }
2265 }
2266 }
2267 $globalKey = (string) crc32($globalKey);
2268 return themify_upload_dir('basedir') . '/themify-concate/' . $globalKey . '/';
2269 }
2270
2271 /** Add schedule four_week
2272 * array $schedules
2273 *
2274 * return array
2275 */
2276 public static function cron_schedules(array $schedules):array {
2277 $schedules['four_week'] = array(
2278 'interval' => WEEK_IN_SECONDS * 4,
2279 'display' => '4 weeks'
2280 );
2281 return $schedules;
2282 }
2283
2284 /** Cron job to remove old concate css files and customizer css files
2285 * return void
2286 */
2287 public static function cron() {
2288
2289 $path = pathinfo(self::getCurrentVersionFolder());
2290 $dir = $path['dirname'] . '/';
2291 if(!class_exists('Themify_Filesystem',false)){
2292 require_once THEMIFY_DIR . '/class-themify-filesystem.php';
2293 }
2294 clearstatcache();
2295 if (Themify_Filesystem::is_dir($dir) && ($handle = opendir($dir))) {
2296 $found=false;
2297 $currentFolder = $path['filename'];
2298 $globalKey = '-' . $currentFolder . '-'; //Need for Backward Compatibility, can be removed 11.05.2021
2299 while (false !== ($f = readdir($handle))) {
2300 if ($f !== '.' && $f !== '..' && $currentFolder !== $f && strpos($f, $globalKey, 5) === false) {
2301 Themify_Filesystem::delete($dir . $f);
2302 $found=true;
2303 }
2304 }
2305 closedir($handle);
2306 unset($currentFolder, $dir, $globalKey);
2307 if($found===true){
2308 TFCache::clear_3rd_plugins_cache();
2309 TFCache::remove_cache();
2310 }
2311 }
2312 unset($path);
2313 $upload_dir = themify_upload_dir('basedir').'/';
2314 $deperecated=$upload_dir.'tf_images_sizes/';
2315 if(Themify_Filesystem::is_dir($deperecated)){
2316 Themify_Filesystem::delete($deperecated);
2317 }
2318 $deperecated=$upload_dir.'tf_image_ids/';
2319 if(Themify_Filesystem::is_dir($deperecated)){
2320 Themify_Filesystem::delete($deperecated);
2321 }
2322 if (self::$themeVersion !== null && Themify_Filesystem::is_dir($upload_dir) && ($handle = opendir($upload_dir))) {//remove old customizer css
2323 $cssFile = THEMIFY_VERSION . '-' . self::$themeVersion;
2324 while (false !== ($f = readdir($handle))) {
2325 if ($f !== '.' && $f !== '..' && strpos($f, 'themify-customizer-') === 0 && strpos($f, $cssFile, 10) === false) {
2326 Themify_Filesystem::delete($upload_dir . $f,'f');
2327 }
2328 }
2329 closedir($handle);
2330 }
2331 Themify_Storage::cleanDb();
2332 }
2333
2334 private static function getPreLoad():string {
2335 $return = '';
2336 if(!empty(self::$preLoadMedia)){
2337 foreach (self::$preLoadMedia as $src => $arr) {
2338 $type=$arr['t'];
2339 $rel=$arr['r'];
2340 // Preload only above-the-fold assets
2341 if($type==='image' && $rel==='preload'){
2342 // Keep preload only when explicitly marked high priority.
2343 if(!isset($arr['i']) || $arr['i']!=='high'){
2344 $rel='prefetch';
2345 unset($arr['i']);
2346 }
2347 }
2348 elseif($type==='style' && $rel==='preload' && isset($arr['i']) && $arr['i']==='low'){
2349 $rel='prefetch';
2350 unset($arr['i']);
2351 }
2352
2353 $type=$arr['t'];
2354 if ($type === 'style' && isset(self::$css[$src])) {
2355 continue;
2356 }
2357 if (isset($arr['v'])) {
2358 $src = $src . '?ver=' . $arr['v'];
2359 }
2360 $extra='';
2361 if($type === 'font'){
2362 $extra=' type="font/' . strtok(pathinfo($src, PATHINFO_EXTENSION), '?') . '" crossorigin';
2363 }
2364 elseif($type === 'image' && isset($arr['srcset'])){
2365 $extra=' imagesrcset="'.$arr['srcset'].'" imagesizes="'.$arr['sizes'].'"';
2366 }
2367 elseif($type=== 'json'){
2368 $extra=' type="application/json" crossorigin="anonymous"';
2369 $type='fetch';
2370 }
2371 if($rel==='prefetch'){
2372 // For prefetch, omit `as` to avoid incorrect type signalling and warnings.
2373 $return .= sprintf('<link rel="prefetch" href="%s">', $src);
2374 }
2375 else{
2376 $return .= sprintf('<link rel="%s" href="%s" as="%s"%s%s>',
2377 $rel,
2378 $src,
2379 $type,
2380 $extra,
2381 (isset($arr['i']) ? ' fetchpriority="' . $arr['i'] . '"' : '')
2382 );
2383 }
2384 }
2385 }
2386 return $return;
2387 }
2388
2389 public static function get_version($url, $ver) {
2390 return $ver;
2391 }
2392
2393 public static function load_search_form_css() {
2394 remove_action('pre_get_search_form', array(__CLASS__, 'load_search_form_css'), 9);
2395 self::add_css('tf_search_form', self::THEMIFY_CSS_MODULES_URI . 'search-form.css', null, THEMIFY_VERSION);
2396 self::addLocalization('done', 'tf_search_form', true);
2397 }
2398
2399 public static function body_open(){
2400 echo '<!--tf_svg_holder-->','<script> </script>';
2401 $ga=themify_get('setting-ga_m_id', '', true);
2402 if($ga!==''){
2403 echo '<noscript><iframe data-no-script src="https://www.googletagmanager.com/ns.html?id=GTM-'.$ga.'" height="0" width="0" style="display:none"></iframe></noscript>',
2404 '<script async data-no-optimize="1" data-noptimize="1" data-cfasync="false" data-ga="'.$ga.'" src="data:text/javascript;base64,KGE9PntmdW5jdGlvbiBlKCl7YS5kYXRhTGF5ZXIucHVzaChhcmd1bWVudHMpfWEuZGF0YUxheWVyPWEuZGF0YUxheWVyfHxbXSxlKCJqcyIsbmV3IERhdGUpLGUoImNvbmZpZyIsZG9jdW1lbnQuY3VycmVudFNjcmlwdC5kYXRhc2V0LmdhKSxlKCJldmVudCIsInBhZ2VfdmlldyIpfSkod2luZG93KTs="></script>',
2405 '<script async data-no-optimize="1" data-noptimize="1" data-cfasync="false" src="https://www.googletagmanager.com/gtag/js?id='.$ga.'"></script>';
2406 }
2407 }
2408
2409 public static function add_theme_support_css($css) {
2410 self::$theme_css_support[$css]=true;
2411 }
2412
2413 public static function remove_theme_support_css($css) {
2414 unset(self::$theme_css_support[$css]);
2415 }
2416
2417 public static function has_theme_support_css($css) {
2418 return isset(self::$theme_css_support[$css]);
2419 }
2420
2421 public static function exclude_main_js( $exclude) {
2422 if(current_filter()==='autoptimize_filter_js_consider_minified'){
2423 if($exclude===false){
2424 $exclude='';
2425 }
2426 if($exclude!=='' && is_array($exclude)){
2427 $exclude[]='themify/';
2428 }
2429 else{
2430 $exclude.='themify/';
2431 }
2432 }
2433 elseif(is_array($exclude)){
2434 $exclude[] = 'themify-main-script';
2435 $exclude[] = 'themify/';
2436 $exclude[] = 'tf_vars';
2437 }
2438 else{
2439 $exclude.= ',themify/';
2440 }
2441 return $exclude;
2442 }
2443
2444 /**
2445 * Exclude Themify scripts from being concatenated in Page Optimize plugin
2446 * @link https://wordpress.org/plugins/page-optimize/
2447 *
2448 * @return bool
2449 */
2450 public static function Automattic_page_optimize_js_exclude(bool $do_concat,string $handle ):bool {
2451 if (strpos( $handle, 'themify' ) !== false|| strpos( $handle, 'tb_' ) !== false) {
2452 return false;
2453 }
2454 return $do_concat;
2455 }
2456 }
2457 add_action( 'init', [ 'Themify_Enqueue_Assets', 'init' ] );
2458