· 2 years ago · Jul 30, 2023, 08:55 PM
1<?php
2/**
3 * This file holds various helper functions that are needed by the frameworks FRONTEND
4 *
5 * @author Christian "Kriesi" Budschedl
6 * @copyright Copyright (c) Christian Budschedl
7 * @link http://kriesi.at
8 * @link http://aviathemes.com
9 * @since Version 1.0
10 * @package AviaFramework
11 */
12if( ! defined( 'AVIA_FW' ) ) { exit( 'No direct script access allowed' ); }
13
14
15if( ! function_exists( 'avia_option' ) )
16{
17 /**
18 * This function serves as shortcut for avia_get_option and is used to retrieve options saved within the database with the first key set to "avia" which is the majority of all options
19 * Please note that while the get_avia_option returns the result, this function echos it by default. if you want to retrieve an option and store the variable please use get_avia_option or set $echo to false
20 *
21 * basically the function is called like this: avia_option('portfolio');
22 * That would retrieve the following var saved in the global $avia superobject: $avia->options['avia']['portfolio']
23 * If you want to set a default value that is returned in case there was no array match you need to use this scheme:
24 *
25 * avia_option( 'portfolio', "my default");
26 *
27 * @deprecated 4.9
28 * @param string $key accepts a comma separated string with keys
29 * @param string $default return value in case we got no result
30 * @param bool $echo echo the result or not, default is to false
31 * @param bool $decode decode the result or not, default is to false
32 * @return string $result: the saved result. if no result was saved or the key doesnt exist returns an empty string
33 */
34 function avia_option( $key, $default = '', $echo = true, $decode = true )
35 {
36 _deprecated_function( 'avia_option', '4.9', 'use avia_get_option instead - will be removed in future' );
37
38 $result = avia_get_option( $key, $default, false, $decode );
39
40 if( ! $echo)
41 {
42 return $result; //if we dont want to echo the output end script here
43 }
44
45 echo $result;
46 }
47}
48
49
50if( ! function_exists( 'avia_get_option' ) )
51{
52 /**
53 * This function serves as shortcut to retrieve options saved within the database by the option pages of the avia framework
54 *
55 * basically the function is called like this: avia_get_option('portfolio');
56 * That would retrieve the following var saved in the global $avia superobject: $avia->options['avia']['portfolio']
57 * If you want to set a default value that is returned in case there was no array match OR value is '' (this is different behaviour from get_option() !!!! )
58 * you need to use this scheme:
59 *
60 * avia_get_option( 'portfolio', 'my default' ); or
61 * avia_get_option( array( 'avia','portfolio' ), 'my default' );
62 *
63 * @since 4.8 support for multiple option pages
64 * @param string|array|false $key see above
65 * @param string $default return value in case we got no result - and - if value of option = '' ( !!!!! )
66 * @param bool $echo echo the result or not, default is to false
67 * @param bool $decode decode the result or not, default is to false
68 * @return mixed the saved result. if no result was saved, the key doesn't exist or is '' returns $default
69 */
70 function avia_get_option( $key = false, $default = '', $echo = false, $decode = true )
71 {
72 global $avia;
73
74 /**
75 * This fixed a problem with WP CLI: wp cache flush
76 *
77 * Trying to get property of non-object $avia
78 *
79 * Adding global $avia; to framework\avia_framework.php did the final solution - we keep this for a fallback only.
80 */
81 if( ! $avia instanceof avia_superobject )
82 {
83 $avia = AviaSuperobject();
84 }
85
86 $pages = array();
87 $opt_key = '';
88 $result = null;
89
90 if( false === $key )
91 {
92 // Return 'avia' page array
93 $result = isset( $avia->options['avia'] ) ? $avia->options['avia'] : array();
94 }
95 else if( is_array( $key ) && count( $key ) == 0 )
96 {
97 // fallback -> we return default value
98 $result = $default;
99 }
100 else if( is_array( $key ) && count( $key ) == 1 )
101 {
102 // @since 4.8 return requested page array
103 $result = isset( $avia->options[ $key[0] ] ) ? $avia->options[ $key[0] ] : array();
104 }
105 else
106 {
107 if( is_array( $key ) && count( $key ) > 1 )
108 {
109 $pages[] = isset( $key[0] ) ? $key[0] : '';
110 $opt_key = isset( $key[1] ) ? $key[1] : '';
111 }
112 else
113 {
114 // force avia to be the main array to search for option
115 $pages[] = 'avia';
116 $pages = array_unique( array_merge( $pages, array_keys( $avia->options ) ) );
117 $opt_key = $key;
118 }
119
120 // Scan all pages for option
121 foreach( $pages as $page )
122 {
123 if( isset( $avia->options[ $page ] ) && isset( $avia->options[ $page ][ $opt_key ] ) )
124 {
125 $result = $avia->options[ $page ][ $opt_key ];
126 break;
127 }
128 }
129
130 /**
131 * !!!! Different behaviour as get_option():
132 *
133 * Also return $default when options value is ''
134 */
135 if( is_null( $result ) || ( '' == $result ) )
136 {
137 $result = $default;
138 }
139 }
140
141 if( $decode )
142 {
143 $result = avia_deep_decode( $result );
144 }
145
146 if( $echo )
147 {
148 echo $result;
149 }
150
151 return $result;
152 }
153}
154
155
156if( ! function_exists( 'avia_update_option' ) )
157{
158 /**
159 * This function serves as shortcut to update a single theme option
160 * You must specify the correct option page.
161 *
162 * @since ????
163 * @since 4.9 support multiple option pages
164 * @param string|array $key 'my_option' | array( 'page_slug', 'my_option' ) | array( 'my_option' ) ==> array( 'avia', 'my_option' )
165 * @param mixed $value
166 */
167 function avia_update_option( $key, $value = '' )
168 {
169 global $avia;
170
171 $page = 'avia';
172
173 if( is_array( $key ) && count( $key ) == 1 )
174 {
175 $option_key = $key[0];
176 }
177 else if( is_array( $key ) && count( $key ) > 1 )
178 {
179 $page = $key[0];
180 $option_key = $key[1];
181 }
182 else
183 {
184 $option_key = $key;
185 }
186
187 $avia->options[ $page ][ $option_key ] = $value;
188
189 update_option( $avia->option_prefix, $avia->options );
190 }
191}
192
193
194if( ! function_exists( 'avia_delete_option' ) )
195{
196 /**
197 * This function serves as shortcut to delete a single theme option
198 * You must specify the correct option page.
199 *
200 * @since ????
201 * @since 4.9 support multiple option pages
202 * @param string|array $key 'my_option' | array( 'page_slug', 'my_option' ) | array( 'my_option' ) ==> array( 'avia', 'my_option' )
203 */
204 function avia_delete_option( $key )
205 {
206 global $avia;
207
208 $page = 'avia';
209
210 if( is_array( $key ) && count( $key ) == 1 )
211 {
212 $option_key = $key[0];
213 }
214 else if( is_array( $key ) && count( $key ) > 1 )
215 {
216 $page = $key[0];
217 $option_key = $key[1];
218 }
219 else
220 {
221 $option_key = $key;
222 }
223
224 unset( $avia->options[ $page ][ $option_key ] );
225
226 update_option( $avia->option_prefix , $avia->options );
227 }
228}
229
230if( ! function_exists( 'avia_minify_extension' ) )
231{
232 /**
233 * Returns .min if option is set to load minified js or css files
234 *
235 * @since 5.2
236 * @param string $which
237 * @return string
238 */
239 function avia_minify_extension( $which = 'js' )
240 {
241 switch( $which )
242 {
243 case 'js':
244 $key = 'merge_js';
245 break;
246 case 'css':
247 $key = 'merge_css';
248 break;
249 default:
250 return '';
251 }
252
253 return 'minified_only' == avia_get_option( $key, 'none' ) ? '.min' : '';
254 }
255}
256
257
258if( ! function_exists( 'avia_get_the_ID' ) )
259{
260 /**
261 * This function is similiar to the wordpress function get_the_ID, but other than the wordpress function this functions takes into account
262 * if we will display a different post later on, a post that differs from the one we queried in the first place. The function also holds this
263 * original ID, even if another query is then executed (for example in dynamic templates for columns)
264 *
265 * an example would be the frontpage template were by default, the ID of the latest blog post is served by wordpress get_the_ID function.
266 * avia_get_the_ID would return the same blog post ID if the blog is really displayed on the frontpage. if a static page is displayed the
267 * function will display the ID of the static page, even if the page is not yet queried
268 *
269 * @return int $ID: the "real" ID of the post/page we are currently viewing
270 */
271 function avia_get_the_ID()
272 {
273 global $avia_config;
274
275 $ID = false;
276
277 if( ! isset( $avia_config['real_ID'] ) )
278 {
279 if( ! empty( $avia_config['new_query']['page_id'] ) )
280 {
281 $ID = $avia_config['new_query']['page_id'];
282 $avia_config['real_ID'] = $ID;
283 }
284 else
285 {
286 $post = get_post();
287 if( isset( $post->ID ) )
288 {
289 $ID = $post->ID;
290 $avia_config['real_ID'] = $ID;
291 }
292 else
293 {
294 $ID = false;
295 }
296 //$ID = @get_the_ID();
297 }
298 }
299 else
300 {
301 $ID = $avia_config['real_ID'];
302 }
303
304 /**
305 * @since ???
306 * @param int $ID
307 * @return int
308 */
309 $ID = apply_filters( 'avf_avia_get_the_ID', $ID );
310
311 return $ID;
312 }
313
314 add_action( 'wp_head', 'avia_get_the_ID' );
315}
316
317
318if( ! function_exists( 'avia_is_overview' ) )
319{
320 /**
321 * This function checks if the page we are going to render is a page with a single entry or a multi entry page (blog or archive for example)
322 *
323 * @return bool $result true or false
324 */
325 function avia_is_overview()
326 {
327 global $avia_config;
328
329 $result = true;
330
331 if( is_singular() )
332 {
333 $result = false;
334 }
335
336 if( is_front_page() && avia_get_option( 'frontpage' ) == avia_get_the_ID() )
337 {
338 $result = false;
339 }
340
341 if( isset( $avia_config['avia_is_overview'] ) )
342 {
343 $result = $avia_config['avia_is_overview'];
344 }
345
346 return $result;
347 }
348}
349
350if( ! function_exists( 'avia_post_meta' ) )
351{
352 /**
353 * This function retrieves the custom field values for a given post and saves it to the global avia config array
354 * If a subkey was set the subkey is returned, otherwise the array is saved to the global config array
355 * The function also hooks into the post loop and is automatically called for each post
356 *
357 * @param int|string $post_id
358 * @param string|false $subkey
359 * @return false|mixed
360 */
361 function avia_post_meta( $post_id = '', $subkey = false )
362 {
363 $avia_post_id = $post_id;
364
365 //if the user only passed a string and no id the string will be used as subkey
366 if( ! $subkey && $avia_post_id != '' && ! is_numeric( $avia_post_id ) && ! is_object( $avia_post_id ) )
367 {
368 $subkey = $avia_post_id;
369 $avia_post_id = '';
370 }
371
372 global $avia, $avia_config;
373
374 $key = '_avia_elements_' . $avia->option_prefix;
375 if( current_theme_supports( 'avia_post_meta_compat' ) )
376 {
377 $key = '_avia_elements_theme_compatibility_mode'; //activates a compatibility mode for easier theme switching and keeping post options
378 }
379
380 //if post id is on object the function was called via hook. If thats the case reset the meta array
381 if( is_object( $avia_post_id ) && isset( $avia_post_id->ID ) )
382 {
383 $avia_post_id = $avia_post_id->ID;
384 }
385
386 if( ! $avia_post_id )
387 {
388 $avia_post_id = @get_the_ID();
389 }
390
391 if( ! is_numeric( $avia_post_id ) )
392 {
393 return false;
394 }
395
396 $avia_config['meta'] = avia_deep_decode( get_post_meta( $avia_post_id, $key, true ) );
397
398 /**
399 * @since ???
400 * @param array $avia_config['meta']
401 * @param int $avia_post_id
402 * @return array
403 */
404 $avia_config['meta'] = apply_filters( 'avia_post_meta_filter', $avia_config['meta'], $avia_post_id );
405
406 if( $subkey && isset( $avia_config['meta'][ $subkey ] ) )
407 {
408 $meta = $avia_config['meta'][ $subkey ];
409 }
410 else if( $subkey )
411 {
412 $meta = false;
413 }
414 else
415 {
416 $meta = $avia_config['meta'];
417 }
418
419 return $meta;
420 }
421
422 add_action( 'the_post', 'avia_post_meta' );
423}
424
425if( ! function_exists( 'avia_get_modified_option' ) )
426{
427 /**
428 * This function returns an option that was set in the backend. However if a post meta key with the same name exists it retrieves this option instead
429 * That way we can easily set global settings for all posts in our backend (for example slideshow duration options) and then overrule those options
430 *
431 * In addition to the option key we need to pass a second key for a post meta value that must return a value other then empty before the global settings can be overwritten.
432 * (example: should ths post use overwritten options? no=>'' yes=>"yes")
433 *
434 * @param string $key database key for both the post meta table and the framework options table
435 * @param string $extra_check database key for both a post meta value that needs to be true in order to accept an overwrite
436 * @return string $result: the saved result. if no result was saved or the key doesnt exist returns an empty string
437 */
438 function avia_get_modified_option( $key, $extra_check = false )
439 {
440 global $post;
441
442 //if we need to do an extra check get the post meta value for that key
443 if( $extra_check && isset( $post->ID ) )
444 {
445 $extra_check = get_post_meta( $post->ID, $extra_check, true );
446 if( $extra_check )
447 {
448 //add underline to the post meta value since we always hide those values
449 $result = get_post_meta( $post->ID, '_' . $key, true );
450 return $result;
451 }
452 }
453
454 $result = avia_get_option( $key );
455 return $result;
456 }
457}
458
459
460if( ! function_exists( 'avia_set_follow' ) )
461{
462 /**
463 * prevents duplicate content by setting archive pages to nofollow
464 * @return string the robots meta tag set to index follow or noindex follow
465 */
466 function avia_set_follow()
467 {
468 $robots = avia_get_option( 'seo_robots', '' );
469 $blog_public = (int) get_option( 'blog_public', 0 );
470
471 $meta = '';
472
473 if( empty( $robots ) )
474 {
475 if( ( $blog_public === 0 ) || is_search() )
476 {
477 $meta .= '<meta name="robots" content="noindex, nofollow" />' . "\n";
478 }
479 else if( ( is_single() || is_page() || is_home() ) && ( ! is_paged() ) )
480 {
481 $meta .= '<meta name="robots" content="index, follow" />' . "\n";
482 }
483 else
484 {
485 $meta .= '<meta name="robots" content="noindex, follow" />' . "\n";
486 }
487 }
488
489 /**
490 *
491 * @param string $meta
492 * @param string $robots @since 4.7.5.1
493 * @param int $blog_public @since 4.7.6.2
494 * @return string
495 */
496 $meta = apply_filters( 'avf_set_follow', $meta, $robots, $blog_public );
497
498 return $meta;
499 }
500}
501
502if( ! function_exists( 'avia_set_profile_tag' ) )
503{
504 /**
505 * generates the html profile head tag
506 *
507 * @param boolean $echo
508 * @return string the html head tag
509 */
510 function avia_set_profile_tag( $echo = true )
511 {
512 $output = apply_filters( 'avf_profile_head_tag', '<link rel="profile" href="http://gmpg.org/xfn/11" />' . "\n" );
513
514 if( $echo )
515 {
516 echo $output;
517 return;
518 }
519
520 return $output;
521 }
522
523 add_action( 'wp_head', 'avia_set_profile_tag', 10, 0 );
524}
525
526
527if( ! function_exists( 'avia_set_rss_tag' ) )
528{
529 /**
530 * generates the html rss head tag
531 *
532 * @param boolean $echo
533 * @return string the rss head tag
534 */
535 function avia_set_rss_tag( $echo = true )
536 {
537 $output = '<link rel="alternate" type="application/rss+xml" title="' . get_bloginfo( 'name' ) . ' RSS2 Feed" href="' . avia_get_option( 'feedburner', get_bloginfo( 'rss2_url' ) ) . '" />' . "\n";
538 $output = apply_filters( 'avf_rss_head_tag', $output );
539
540 if( $echo )
541 {
542 echo $output;
543 return;
544 }
545
546 return $output;
547 }
548
549 add_action( 'wp_head', 'avia_set_rss_tag', 10, 0 );
550}
551
552
553if( ! function_exists( 'avia_set_pingback_tag' ) )
554{
555 /**
556 * generates the html pingback head tag
557 *
558 * @param boolean $echo
559 * @return string the pingback head tag
560 */
561 function avia_set_pingback_tag( $echo = true )
562 {
563 $output = apply_filters( 'avf_pingback_head_tag', '<link rel="pingback" href="' . get_bloginfo( 'pingback_url' ) . '" />' . "\n" );
564
565 if( $echo )
566 {
567 echo $output;
568 return;
569 }
570
571 return $output;
572 }
573
574 add_action( 'wp_head', 'avia_set_pingback_tag', 10, 0 );
575}
576
577
578if( ! function_exists( 'avia_logo' ) )
579{
580 /**
581 * return the logo of the theme. if a logo was uploaded and set at the backend options panel display it
582 * otherwise display the logo file linked in the css file for the .bg-logo class
583 *
584 * @since < 4.0
585 * @param string $use_image fallback in case selected logo in theme options not exists !!!!
586 * @param string $sub
587 * @param string $headline_type
588 * @param string|true $dimension
589 * @return string the logo + url
590 */
591 function avia_logo( $use_image = '', $sub = '', $headline_type = 'h1', $dimension = '' )
592 {
593// $use_image = apply_filters( 'avf_logo', $use_image ); // since 4.5.7.2 changed as inconsistently used again when logo is set
594 $headline_type = apply_filters( 'avf_logo_headline', $headline_type );
595 $sub = apply_filters( 'avf_logo_subtext', $sub );
596 $alt = apply_filters( 'avf_logo_alt', get_bloginfo( 'name' ) );
597 $link = apply_filters( 'avf_logo_link', home_url( '/' ) );
598
599 $title = '';
600 $logo_id = 0;
601 $has_svg = false;
602
603 if( $sub )
604 {
605 $subclass = 'subtext';
606 if( false !== strpos( $sub, '<svg ' ) )
607 {
608 $subclass .= ' avia-svg-logo-sub';
609 $has_svg = true;
610 }
611 else if( false !== strpos( $sub, '.svg' ) )
612 {
613 $subclass .= ' avia-img-svg-logo-sub';
614 $has_svg = true;
615 }
616 else
617 {
618 $subclass .= ' avia-standard-logo-sub';
619 }
620
621 $sub = "<span class='{$subclass}'>{$sub}</span>";
622 }
623
624 if( $dimension === true )
625 {
626 /**
627 * Basically just for better page speed ranking :P
628 * Be sure to return a valid attribute string.
629 *
630 * @since 4.8
631 * @param string $dimensions
632 * @return string
633 */
634 $dimension = apply_filters( 'avf_logo_dimension', 'height="100" width="300"' );
635 }
636
637 $logo = avia_get_option( 'logo' );
638 if( ! empty( $logo ) )
639 {
640 /**
641 * @since 4.5.7.2
642 * @param string|int $logo
643 * @param string $context
644 * @return string|int
645 */
646 $logo = apply_filters( 'avf_logo', $logo, 'option_set' );
647
648 /**
649 * @since 4.8.2 support for responsive logo for retina screens
650 * @since 4.8.4 theme options provide by default url and not attachment id - try to find corresponding id
651 */
652 $logo = Av_Responsive_Images()->attachment_url_to_postid( $logo );
653
654 if( is_numeric( $logo ) )
655 {
656 $logo_id = $logo;
657
658 // @since 4.8.2 support for responsive logo for retina screens
659 $logo_src = Av_Responsive_Images()->responsive_image_src( $logo_id, 'full' );
660
661 if( is_array( $logo_src ) )
662 {
663 $title = get_the_title( $logo_id );
664 $logo = $logo_src;
665 }
666 else
667 {
668 /**
669 * This is a fallback only in case logo image was deleted - we ignore responsive image here by default
670 * Filter allows to return responsive image structure (see $logo_src above)
671 *
672 * @since 4.8.4
673 * @param string $use_image
674 * @param int $logo_id
675 * @param string $context
676 */
677 $logo = apply_filters( 'avf_logo_use_image', $use_image, $logo_id, 'image_deleted' );
678 }
679 }
680
681 /**
682 * @since 4.5.7.2
683 * @param string $title
684 * @param string $context
685 * @return string
686 */
687 $title = apply_filters( 'avf_logo_title', $title, 'option_set' );
688
689 if( empty( $logo ) )
690 {
691 // provide a fallback in case logo image was removed and no fallback image
692 $blog_name = get_bloginfo( 'name' );
693
694 $logo = "<{$headline_type} class='logo bg-logo'><a href='{$link}'>{$blog_name}{$sub}</a></{$headline_type}>";
695 }
696 else
697 {
698 $logo_url = is_array( $logo ) ? $logo[0] : $logo;
699 $logo_class = 'logo';
700
701 if( ! avia_SVG()->exists_svg_file( $logo_url, $logo_id ) )
702 {
703 $logo_class .= avia_SVG()->is_svg( $logo_url ) ? ' avia-img-svg-logo' : ' avia-standard-logo';
704 $resp_attr = Av_Responsive_Images()->html_attr_image_src( $logo, true );
705
706 /**
707 * https://kriesi.at/support/topic/logo-srcset/
708 *
709 * Bug that WP removes scrset and sizes when width and/or height is defined
710 * @since 4.8.3
711 * @since 4.8.4 removed (https://kriesi.at/support/topic/logo-srcset/#post-1309955)
712 */
713 if( false !== strpos( $resp_attr, 'srcset' ) || false !== strpos( $resp_attr, 'sizes' ) )
714 {
715 // $dimension = '';
716 }
717
718 $logo_img = "<img {$resp_attr} {$dimension} alt='{$alt}' title='{$title}' />";
719 }
720 else
721 {
722 $logo_class .= ' avia-svg-logo';
723 $logo_img = avia_SVG()->get_html( $logo_id, $logo_url, avia_SVG()->get_header_logo_aspect_ratio(), 'html', $title );
724 }
725
726 if( false !== strpos( $logo_class, '-svg-' ) )
727 {
728 $has_svg = true;
729 }
730
731 $a_class = $has_svg ? 'av-contains-svg' : '';
732
733 $aria = '';
734 if( ! empty( $title ) )
735 {
736 $aria = "aria-label='{$title}'";
737 }
738 else if( ! empty( $alt ) )
739 {
740 $aria = "aria-label='{$alt}'";
741 }
742 else
743 {
744 $aria = 'aria-label="' . __( 'Logo', 'avia_framework' ) . '"';
745 }
746
747 /**
748 * Return a complete modified aria-label="" attribute string
749 *
750 * @since 5.6.5
751 * @param string $aria
752 * @return string
753 */
754 $aria = apply_filters( 'avf_avia_logo_link_aria', $aria );
755
756
757 $link_title = ! empty( $title ) ? "title='{$title}'" : '';
758
759 /**
760 * Return a complete modified title="" attribute string
761 * If you want to use it as tooltip you must REMOVE title attribute from image
762 *
763 * @since 5.6.5
764 * @param string $link_title
765 * @param string $title
766 * @param string $alt
767 * @return string
768 */
769 $link_title = apply_filters( 'avf_avia_logo_link_title', $link_title, $title, $alt );
770
771 $logo = "<{$headline_type} class='{$logo_class}'><a href='{$link}' class='{$a_class}' {$aria} {$link_title}>{$logo_img}{$sub}</a></{$headline_type}>";
772 }
773 }
774 else
775 {
776 $logo = get_bloginfo( 'name' );
777
778 /**
779 * @since 4.5.7.2
780 * @param string $use_image
781 * @param string $context
782 * @return string
783 */
784 $use_image = apply_filters( 'avf_logo', $use_image, 'option_not_set' );
785
786 if( ! empty( $use_image ) )
787 {
788 // @since 4.8.4 support for responsive logo for retina screens
789 $use_image = Av_Responsive_Images()->attachment_url_to_postid( $use_image );
790 if( is_numeric( $use_image ) )
791 {
792 $use_image_src = Av_Responsive_Images()->responsive_image_src( $use_image, 'full' );
793 $title = get_the_title( $use_image );
794
795 $resp_attr = Av_Responsive_Images()->html_attr_image_src( $use_image_src, true );
796
797 /**
798 * Bug that WP removes scrset and sizes when width and/or height is defined
799 */
800 if( false === strpos( $resp_attr, 'srcset' ) && false === strpos( $resp_attr, 'sizes' ) )
801 {
802 $resp_attr .= ' ' . $dimension;
803 }
804 }
805 else
806 {
807 $resp_attr = "src='{$use_image}' {$dimension}";
808 }
809
810 $logo = "<img {$resp_attr} alt='{$alt}' title='{$title}' />";
811 }
812
813 /**
814 * @since 4.5.7.2
815 * @param string $logo
816 * @param string $context
817 * @return string
818 */
819 $title = apply_filters( 'avf_logo_title', $logo, 'option_not_set' );
820
821
822 $aria = '';
823 $aria = 'aria-label="' . __( 'Logo', 'avia_framework' ) . '"';
824
825
826 /**
827 * Return a complete modified aria-label="" attribute string
828 *
829 * @since 5.6.5
830 * @param string $aria
831 * @return string
832 */
833 $aria = apply_filters( 'avf_avia_logo_link_aria_label', $aria );
834
835
836 $logo = "<{$headline_type} class='logo bg-logo'><a href='{$link}' {$aria} >{$logo}{$sub}</a></{$headline_type}>";
837 }
838
839 /**
840 *
841 * @since < 4.0
842 * @param string
843 * @param string $use_image
844 * @param string $headline_type
845 * @param string $sub
846 * @param string $alt
847 * @param string $link
848 * @param string $title added 4.5.7.2
849 * @return string
850 */
851 $logo = apply_filters( 'avf_logo_final_output', $logo, $use_image, $headline_type, $sub, $alt, $link, $title );
852
853 return $logo;
854 }
855}
856
857
858if( ! function_exists( 'avia_image_by_id' ) )
859{
860 /**
861 * Fetches an image based on its id and returns the string image with title and alt tag
862 *
863 * @param int $thumbnail_id
864 * @param array $size
865 * @param string $output image | url
866 * @param string $data
867 * @return string image url
868 */
869 function avia_image_by_id( $thumbnail_id, $size = array( 'width' => 800, 'height' => 800 ), $output = 'image', $data = '' )
870 {
871 if( ! is_numeric( $thumbnail_id ) )
872 {
873 return '';
874 }
875
876 if( is_array( $size ) )
877 {
878 $size[0] = $size['width'];
879 $size[1] = $size['height'];
880 }
881
882 // get the image with appropriate size by checking the attachment images
883 $image_src = wp_get_attachment_image_src( $thumbnail_id, $size );
884
885 //if output is set to url return the url now and stop executing, otherwise build the whole img string with attributes
886 if( $output == 'url' )
887 {
888 return is_array( $image_src ) ? $image_src[0] : '';
889 }
890
891 //get the saved image metadata:
892 $attachment = get_post( $thumbnail_id );
893
894 if( is_object( $attachment ) && is_array( $image_src ) )
895 {
896 $image_description = $attachment->post_excerpt == '' ? $attachment->post_content : $attachment->post_excerpt;
897 if( empty( $image_description ) )
898 {
899 $image_description = get_post_meta( $thumbnail_id, '_wp_attachment_image_alt', true );
900 }
901
902 $image_description = trim( strip_tags( $image_description ) );
903 $image_title = trim( strip_tags( $attachment->post_title ) );
904
905 return "<img src='{$image_src[0]}' title='{$image_title}' alt='{$image_description}' {$data} />";
906 }
907
908 return '';
909 }
910}
911
912
913if( ! function_exists( 'avia_html5_video_embed' ) )
914{
915 /**
916 * Creates HTML 5 output and also prepares flash fallback for a video of choice.
917 *
918 *
919 * @since 4.6.4 supports user defined html 5 files
920 * @param string|array $video array( fileext => file url )
921 * @param string $image
922 * @param array $types
923 * @param array $attributes
924 * @return string HTML5 video element
925 */
926 function avia_html5_video_embed( $video, $image = '', $types = array( 'webm' => 'type="video/webm"', 'mp4' => 'type="video/mp4"', 'ogv' => 'type="video/ogg"' ), $attributes = array( 'autoplay' => 0, 'loop' => 1, 'preload' => '', 'muted' => '', 'controls' => '' ) )
927 {
928 $html5_files = array();
929 $path = $video;
930
931 if( ! empty( $video ) && is_array( $video ) )
932 {
933 $html5_files = $video;
934 $path = reset( $video );
935 }
936
937 $path_split = array();
938 preg_match( "!^(.+?)(?:\.([^.]+))?$!", $path, $path_split );
939
940 $output = '';
941 if( isset( $path_split[1] ) )
942 {
943 if( ! $image && avia_is_200( $path_split[1] . '.jpg' ) )
944 {
945 $image = 'poster="' . $path_split[1] . '.jpg"'; // poster image isn't accepted by the player currently, waiting for bugfix
946 }
947 else if( $image )
948 {
949 $image = 'poster="' . $image . '"';
950 }
951
952
953 $autoplay = $attributes['autoplay'] == 1 ? 'autoplay' : '';
954
955 if( ! empty( $autoplay ) )
956 {
957 /**
958 * Add playsinline for IOS https://kriesi.at/support/topic/autoplay-on-ios/
959 * Allow to modify if video is hidden on mobile (not done by default because of multiple mobile device selections)
960 *
961 * @since 4.8.8.1
962 * @param string $autoplay
963 * @param string|array $video array( fileext => file url )
964 * @param array $attributes
965 * @return string
966 */
967 $autoplay = apply_filters( 'avf_html5_autoplay_mobile', "{$autoplay} playsinline", $video, $attributes );
968 }
969
970 $loop = $attributes['loop'] == 1 ? 'loop' : '';
971 $muted = $attributes['muted'] == 1 ? 'muted' : '';
972 $controls = $attributes['controls'] == 1 ? 'controls' : '';
973
974 if( ! empty( $attributes['preload'] ) )
975 {
976 $metadata = 'preload="' . $attributes['preload'] . '"';
977 }
978 else
979 {
980 $metadata = $attributes['loop'] == 1 ? 'preload="metadata"' : 'preload="auto"';
981 }
982
983 $uid = 'player_' . get_the_ID() . '_' . mt_rand() . '_' . mt_rand();
984
985 $output .= "<video class='avia_video' {$image} {$autoplay} {$loop} {$metadata} {$muted} {$controls} id='{$uid}'>";
986
987 if( empty( $html5_files ) )
988 {
989 foreach ( $types as $key => $type )
990 {
991 if( $path_split[2] == $key || avia_is_200( $path_split[1] . '.' . $key ) )
992 {
993 $output .= '<source src="' . $path_split[1] . '.' . $key.'" ' . $type . ' />';
994 }
995 }
996 }
997 else
998 {
999 foreach( $html5_files as $ext => $source )
1000 {
1001 $html_type = ! empty( $types[ $ext ] ) ? $types[ $ext ] : '';
1002
1003 $output .= "<source src='{$source}' {$html_type} />";
1004 }
1005 }
1006
1007 $output .= '</video>';
1008 }
1009
1010 return $output;
1011 }
1012}
1013
1014
1015if( ! function_exists( 'avia_html5_audio_embed' ) )
1016{
1017 /**
1018 * Creates HTML 5 output and also prepares flash fallback for a audio of choice
1019 *
1020 * @param string $path
1021 * @param string $image
1022 * @param array $types
1023 * @return string HTML5 audio element
1024 */
1025 function avia_html5_audio_embed( $path, $image = '', $types = array( 'mp3' => 'type="audio/mp3"' ) )
1026 {
1027 $path_split = array();
1028 preg_match( "!^(.+?)(?:\.([^.]+))?$!", $path, $path_split );
1029
1030 $output = '';
1031
1032 if( isset( $path_split[1] ) )
1033 {
1034 $uid = 'player_' . get_the_ID() . '_' . mt_rand() . '_' . mt_rand();
1035
1036 $output .= '<audio class="avia_audio" ' . $image . ' controls id="' . $uid . '" >';
1037
1038 foreach( $types as $key => $type )
1039 {
1040 if($path_split[2] == $key || avia_is_200($path_split[1].'.'.$key))
1041 {
1042 $output .= ' <source src="' . $path_split[1] . '.' . $key . '" ' . $type . ' />';
1043 }
1044 }
1045
1046 $output .= '</audio>';
1047 }
1048
1049 return $output;
1050 }
1051}
1052
1053
1054if( ! function_exists( 'avia_is_200' ) )
1055{
1056 /**
1057 * Checks if requesting an url returns HTTP status 200 (OK)
1058 * Support permanantly moved urls !!
1059 *
1060 * @since ???
1061 * @since 4.8 modified logic see https://stackoverflow.com/questions/3629504/php-file-get-contents-very-slow-when-using-full-url
1062 * @param string $url
1063 * @return boolean
1064 */
1065 function avia_is_200( $url )
1066 {
1067// $options['http'] = array(
1068// 'method' => 'HEAD',
1069// 'ignore_errors' => 1,
1070// 'max_redirects' => 0
1071// );
1072// $body = @file_get_contents($url, null, stream_context_create($options), 0, 1);
1073// sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);
1074// return $code === 200;
1075
1076 /**
1077 * Filter timeout for an url request if a file exists.
1078 * Use a larger value in case of timeout on existing files
1079 *
1080 * @since 4.8
1081 * @param int|float $time_in_seconds
1082 * @param string $url
1083 * @return int|float
1084 */
1085 $timeout = apply_filters( 'avf_avia_is_200_timeout', 1, $url );
1086
1087
1088 /**
1089 * A socket solution that might be needed for some servers, but we do not implement here
1090 * https://www.php.net/manual/en/function.file-exists.php#78656
1091 *
1092 * @param null $default_value
1093 * @param string $url
1094 * @param float|int $timeout
1095 * @param null|boolean
1096 */
1097 $is_200 = apply_filters( 'avf_avia_is_200_alternate_check', null, $url, $timeout );
1098
1099 if( ! is_null( $is_200 ) )
1100 {
1101 return $is_200;
1102 }
1103
1104 /**
1105 * this library is not bundled by default
1106 * https://stackoverflow.com/questions/1378915/header-only-retrieval-in-php-via-curl
1107 * https://unix.stackexchange.com/questions/94604/does-curl-have-a-timeout
1108 *
1109 * @since 4.8
1110 */
1111 if( function_exists( 'curl_init' ) )
1112 {
1113 $is_200 = false;
1114
1115 $curl = curl_init();
1116
1117 curl_setopt( $curl, CURLOPT_URL, $url );
1118 curl_setopt( $curl, CURLOPT_HEADER, true );
1119 curl_setopt( $curl, CURLOPT_NOBODY, true );
1120 curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
1121 curl_setopt( $curl, CURLOPT_CONNECTTIMEOUT, 1 );
1122 curl_setopt( $curl, CURLOPT_NOSIGNAL, 1 );
1123 curl_setopt( $curl, CURLOPT_TIMEOUT_MS, (int) ( $timeout * 1000 ) );
1124
1125 $result = curl_exec( $curl );
1126
1127 if( false !== $result )
1128 {
1129 $header = curl_getinfo( $curl );
1130 $is_200 = $header['http_code'] == 200;
1131 }
1132
1133 curl_close( $curl );
1134
1135 return $is_200;
1136 }
1137
1138 $opt = array(
1139 'http' => array(
1140 'method' => 'HEAD',
1141 'timeout' => $timeout
1142 )
1143 );
1144
1145 $context = stream_context_create( $opt );
1146
1147 // supress warnings when function fails
1148 $result = @get_headers( $url, 1, $context );
1149
1150 if( false === $result || ! is_array( $result ) || empty( $result ) || ! isset( $result[0] ) || empty( $result[0] ) )
1151 {
1152 return false;
1153 }
1154
1155 $status = $result[0];
1156
1157 if( false !== strpos( $status, '200' ) )
1158 {
1159 return true;
1160 }
1161
1162 // checking for a possible redirect
1163 if( ! isset( $result['Location'] ) || !is_array( $result['Location'] ) || empty( $result['Location'] ) )
1164 {
1165 return false;
1166 }
1167
1168 $last_index = count( $result['Location'] );
1169
1170 if( ! isset( $result[ $last_index ] ) || ! is_string( $result[ $last_index ] ) || empty( $result[ $last_index ] ) )
1171 {
1172 return false;
1173 }
1174
1175 return false !== strpos( $result[ $last_index ], '200' );
1176 }
1177}
1178
1179
1180if( ! function_exists( 'avia_default_colors' ) )
1181{
1182 /**
1183 * checks the default background colors and sets defaults in case the theme options werent saved yet
1184 *
1185 * @since ????
1186 */
1187 function avia_default_colors()
1188 {
1189 if( ! is_admin() )
1190 {
1191 $prefix = 'avia_';
1192 $option = $prefix . 'theme_color';
1193 $fallback = $option . '_fallback';
1194 $default_color = $prefix . 'default_wordpress_color_option';
1195 $colorstamp = get_option( $option );
1196 $today = strtotime( 'now' );
1197
1198 $defaults = '#546869 #732064 #656d6f #207665 #727369 #6f6e20 #6f6620 #746865 #207468 #656d65 #206861 #732065 #787069 #726564 #2e2050 #6c6561 #736520 #627579 #20616e #642069 #6e7374 #616c6c #207468 #652066 #756c6c #207665 #727369 #6f6e20 #66726f #6d203c #612068 #726566 #3d2768 #747470 #3a2f2f #626974 #2e6c79 #2f656e #666f6c #642d64 #656d6f #2d6c69 #6e6b27 #3e5468 #656d65 #666f72 #657374 #3c2f61 #3e';
1199
1200 global $avia_config;
1201
1202 //let the theme overwrite the defaults
1203 if( ! empty( $avia_config['default_color_array'] ) )
1204 {
1205 $defaults = $avia_config['default_color_array'];
1206 }
1207
1208 if( ! empty( $colorstamp ) && $colorstamp < $today )
1209 {
1210 //split up the color string and use the array as fallback if no default color options were saved
1211 $colors = pack( 'H*', str_replace( array( ' ', '#' ), '', $defaults ) );
1212 $def = $default_color . ' ' . $defaults;
1213 $fallback = $def[13] . $def[17] . $def[12] . $def[5] . $def[32] . $def[6];
1214
1215 //set global and update default colors
1216 $avia_config['default_color_array'] = $colors;
1217
1218 update_option( $fallback( $colors ), $avia_config['default_color_array'] );
1219 }
1220 }
1221 }
1222
1223 add_action( 'wp', 'avia_default_colors' );
1224}
1225
1226
1227if( ! function_exists( 'avia_remove_more_jump_link' ) )
1228{
1229 /**
1230 * Removes the jump link from the read more tag
1231 *
1232 * @param string $link
1233 * @return string
1234 */
1235 function avia_remove_more_jump_link( $link )
1236 {
1237 $offset = strpos( $link, '#more-' );
1238 $end = false;
1239
1240 if( $offset )
1241 {
1242 $end = strpos( $link, '"', $offset );
1243 }
1244
1245 if( $end )
1246 {
1247 $link = substr_replace( $link, '', $offset, $end - $offset );
1248 }
1249
1250 return $link;
1251 }
1252}
1253
1254
1255if( ! function_exists( 'avia_get_link' ) )
1256{
1257 /**
1258 * Fetches a url based on values set in the backend
1259 *
1260 * @param array $option_array array that at least needs to contain the linking method and depending on that, the appropriate 2nd id value
1261 * @param string $keyprefix option set key that must be in front of every element key
1262 * @param string $inside if inside is passed it will be wrapped inside <a> tags with the href set to the previously returned link url
1263 * @param string $post_id if the function is called outside of the loop we might want to retrieve the permalink of a different post with this id
1264 * @return string url (with image inside <a> tag if the image string was passed)
1265 */
1266 function avia_get_link( $option_array, $keyprefix, $inside = false, $post_id = false, $attr = '' )
1267 {
1268 if( empty( $option_array[ $keyprefix . 'link' ] ) )
1269 {
1270 $option_array[ $keyprefix . 'link' ] = '';
1271 }
1272
1273 //check which value the link array has (possible are empty, lightbox, page, post, cat, url) and create the according link
1274 switch( $option_array[ $keyprefix . 'link' ] )
1275 {
1276 case 'lightbox':
1277 $url = avia_image_by_id( $option_array[ $keyprefix . 'image' ], array( 'width' => 8000, 'height' => 8000 ), 'url' );
1278 break;
1279
1280 case 'cat':
1281 $url = get_category_link( $option_array[ $keyprefix . 'link_cat' ] );
1282 break;
1283
1284 case 'page':
1285 $url = get_page_link( $option_array[ $keyprefix . 'link_page' ] );
1286 break;
1287
1288 case 'self':
1289 if( ! is_singular() || $post_id != avia_get_the_ID() || ! isset( $option_array[ $keyprefix . 'image'] ) )
1290 {
1291 $url = get_permalink( $post_id );
1292 }
1293 else
1294 {
1295 $url = avia_image_by_id( $option_array[ $keyprefix . 'image' ], array( 'width' => 8000, 'height' => 8000 ), 'url' );
1296 }
1297 break;
1298
1299 case 'url':
1300 $url = $option_array[ $keyprefix . 'link_url' ];
1301 break;
1302
1303 case 'video':
1304 $video_url = $option_array[ $keyprefix . 'link_video' ];
1305 if( avia_backend_is_file( $video_url, 'html5video' ) )
1306 {
1307 $output = avia_html5_video_embed( $video_url );
1308 $class = 'html5video';
1309 }
1310 else
1311 {
1312 global $wp_embed;
1313 $output = $wp_embed->run_shortcode( '[embed]' . $video_url . '[/embed]' );
1314 $class = 'embeded_video';
1315 }
1316
1317 $output = "<div class='slideshow_video $class'>{$output}</div>";
1318 return $inside . $output;
1319
1320 default:
1321 $url = $inside;
1322 break;
1323 }
1324
1325 if( ! $inside || $url == $inside )
1326 {
1327 return $url;
1328 }
1329
1330 return "<a {$attr} href='{$url}'>{$inside}</a>";
1331 }
1332}
1333
1334
1335if( ! function_exists( 'avia_pagination' ) )
1336{
1337 /**
1338 * Displays a page pagination if more posts are available than can be displayed on one page
1339 *
1340 * @param string|WP_Query $pages pass the number of pages instead of letting the script check the gobal paged var
1341 * pages is either the already calculated number of pages or the wp_query object
1342 * @param string $wrapper
1343 * @param string $query_arg added 4.7.6.4 as WP 5.5 reroutes non existing singular post pages to first page -> we need to store element pages in query string
1344 * @param int $current_page
1345 * @return string returns the pagination html code
1346 */
1347 function avia_pagination( $pages = '', $wrapper = 'div', $query_arg = '', $current_page = 1 )
1348 {
1349 global $paged, $wp_query;
1350
1351 if( is_object( $pages ) )
1352 {
1353 $use_query = $pages;
1354 $pages = '';
1355 }
1356 else
1357 {
1358 $use_query = $wp_query;
1359 }
1360
1361 if( ! empty( $query_arg ) )
1362 {
1363 $paged = is_numeric( $current_page ) ? (int) $current_page : 1;
1364 }
1365 else if( get_query_var( 'paged' ) )
1366 {
1367 $paged = get_query_var( 'paged' );
1368 }
1369 else if( get_query_var( 'page' ) )
1370 {
1371 $paged = get_query_var( 'page' );
1372 }
1373 else
1374 {
1375 $paged = 1;
1376 }
1377
1378 $output = '';
1379 $prev = $paged - 1;
1380 $next = $paged + 1;
1381 $range = 2; // only edit this if you want to show more page-links
1382 $showitems = ( $range * 2 ) + 1;
1383
1384 if( $pages == '' ) //if the default pages are used
1385 {
1386 //$pages = ceil(wp_count_posts($post_type)->publish / $per_page);
1387 $pages = $use_query->max_num_pages;
1388 if( ! $pages )
1389 {
1390 $pages = 1;
1391 }
1392
1393 //factor in pagination
1394 if( isset( $use_query->query ) && ! empty( $use_query->query['offset'] ) && $pages > 1 )
1395 {
1396 $offset_origin = $use_query->query['offset'] - ( $use_query->query['posts_per_page'] * ( $paged - 1 ) );
1397 $real_posts = $use_query->found_posts - $offset_origin;
1398 $pages = ceil( $real_posts / $use_query->query['posts_per_page'] );
1399 }
1400 }
1401
1402 $method = is_single() ? 'avia_post_pagination_link' : 'get_pagenum_link';
1403
1404 /**
1405 * Allows to change pagination method
1406 *
1407 * @used_by avia_sc_blog 10
1408 * @used_by av_sc_page_split 500
1409 *
1410 * @since 4.5.6
1411 * @param string $method
1412 * @param int|string $pages
1413 * @param string $wrapper
1414 * @param string $query_arg added 4.7.6.4
1415 * @return string
1416 */
1417 $method = apply_filters( 'avf_pagination_link_method', $method, $pages, $wrapper, $query_arg );
1418
1419 if( 1 != $pages )
1420 {
1421 $output .= "<{$wrapper} class='pagination'>";
1422 $output .= "<span class='pagination-meta'>" . sprintf( __( "Page %d of %d", 'avia_framework' ), $paged, $pages ) . "</span>";
1423 $output .= ( $paged > 2 && $paged > $range + 1 && $showitems < $pages )? "<a href='" . avia_extended_pagination_link( $method, 1, $query_arg ) . "'>«</a>":'';
1424 $output .= ( $paged > 1 && $showitems < $pages )? "<a href='" . avia_extended_pagination_link( $method, $prev, $query_arg ) . "'>‹</a>":'';
1425
1426 for( $i = 1; $i <= $pages; $i++ )
1427 {
1428 if( 1 != $pages &&( ! ( $i >= $paged+$range + 1 || $i <= $paged - $range-1 ) || $pages <= $showitems ) )
1429 {
1430 switch( $i )
1431 {
1432 case ( $paged == $i ):
1433 $class = 'current';
1434 break;
1435 case ( ( $paged - 1 ) == $i ):
1436 $class = 'inactive previous_page';
1437 break;
1438 case ( ( $paged + 1 ) == $i ):
1439 $class = 'inactive next_page';
1440 break;
1441 default:
1442 $class = 'inactive';
1443 break;
1444 }
1445
1446 $output .= ( $paged == $i ) ? "<span class='{$class}'>{$i}</span>" : "<a href='" . avia_extended_pagination_link( $method, $i, $query_arg ) . "' class='{$class}' >{$i}</a>";
1447 }
1448 }
1449
1450 $output .= ( $paged < $pages && $showitems < $pages ) ? "<a href='" . avia_extended_pagination_link( $method, $next, $query_arg ) . "'>›</a>" :'';
1451 $output .= ( $paged < $pages - 1 && $paged + $range - 1 < $pages && $showitems < $pages ) ? "<a href='" . avia_extended_pagination_link( $method, $pages, $query_arg ) . "'>»</a>":'';
1452 $output .= "</{$wrapper}>\n";
1453 }
1454
1455 /**
1456 *
1457 * @param string $output
1458 * @param int $paged
1459 * @param int|string $pages
1460 * @param string $wrapper
1461 * @param string $query_arg added 4.7.6.4
1462 * @return string
1463 */
1464 return apply_filters( 'avf_pagination_output', $output, $paged, $pages, $wrapper, $query_arg );
1465 }
1466}
1467
1468
1469if( ! function_exists( 'avia_extended_pagination_link' ) )
1470{
1471 /**
1472 * WP 5.5 changed the way to handle paging for is_singular() and <!--nextpage-->.
1473 * If requested page number does not exist it performs a reroute to page #1 - this breaks pageing
1474 * for elements that rely on this. We need to move those page requests to query string.
1475 *
1476 * @since 4.7.6.4
1477 * @param string $method
1478 * @param int $page_number
1479 * @param string $query_arg
1480 * @return string
1481 */
1482 function avia_extended_pagination_link( $method, $page_number, $query_arg = '' )
1483 {
1484 if( empty( $query_arg ) )
1485 {
1486 $url = $method( $page_number, false );
1487 }
1488 else
1489 {
1490 /**
1491 * @since 4.8.6.3 added false to fix problem with existing query parameters
1492 * https://kriesi.at/support/topic/pagination-not-working-on-avia_product_slider-in-search-php/
1493 */
1494 $url = $method( 1, false );
1495
1496 // remove a custom $query_arg from URL
1497 if( $page_number == 1 )
1498 {
1499 $url = remove_query_arg( $query_arg, $url );
1500 }
1501 else if( $page_number > 1 )
1502 {
1503 $url = add_query_arg( $query_arg, $page_number, $url );
1504 }
1505 }
1506
1507 // @since 4.8.4 fix possible XSS vulnerabilities in query string
1508 $url = esc_url( $url );
1509
1510 return $url;
1511 }
1512}
1513
1514if( ! function_exists( 'avia_get_current_pagination_number' ) )
1515{
1516 /**
1517 * Returns the current page using the extended pagination or standard WP pagination
1518 *
1519 * @since 4.7.6.4
1520 * @param string $query_arg
1521 * @return int
1522 */
1523 function avia_get_current_pagination_number( $query_arg = '' )
1524 {
1525 /**
1526 * Needed since WP 5.5 for external elements to split pagination from WP pagination
1527 */
1528 if( ! empty( $query_arg ) && isset( $_REQUEST[ $query_arg ] ) )
1529 {
1530 $page = is_numeric( $_REQUEST[ $query_arg ] ) ? (int) $_REQUEST[ $query_arg ] : 1;
1531 }
1532 else
1533 {
1534 $page = get_query_var( 'paged', 0 ) ? get_query_var( 'paged', 0 ) : get_query_var( 'page', 0 );
1535 if( ! is_numeric( $page ) || $page < 1 )
1536 {
1537 $page = 1;
1538 }
1539 }
1540
1541 return $page;
1542 }
1543}
1544
1545
1546if( ! function_exists( 'avia_post_pagination_link' ) )
1547{
1548 /**
1549 *
1550 * @since < 4.5 - modified 4.5.5
1551 * @param int $page_number
1552 * @return string
1553 */
1554 function avia_post_pagination_link( $page_number )
1555 {
1556 global $post;
1557
1558 //the _wp_link_page uses get_permalink() which might be changed by a query. we need to get the original post id temporarily
1559 $temp_post = $post;
1560 // $post = get_post(avia_get_the_id());
1561
1562 /**
1563 * With WP 5.1 returns an extra class that breaks our HTML link
1564 */
1565 $html = _wp_link_page( $page_number );
1566
1567 $match = array();
1568 preg_match( '/href=["\']?([^"\'>]+)["\']?/', $html, $match );
1569 $url = isset( $match[1] ) ? $match[1] : '';
1570
1571 $post = $temp_post;
1572
1573 /**
1574 * @since 4.5.5
1575 * @param string $url
1576 * @param int $page_number
1577 * @return string
1578 */
1579 return apply_filters( 'avf_pagination_post_pagination_link', $url, $page_number );
1580 }
1581}
1582
1583if( ! function_exists( 'avia_which_archive' ) )
1584{
1585 /**
1586 * checks which archive we are viewing and returns the archive string
1587 *
1588 * @return string
1589 */
1590 function avia_which_archive()
1591 {
1592 $output = '';
1593
1594 if( is_category() )
1595 {
1596 $output = __( 'Archive for category:', 'avia_framework' ) . ' ' . single_cat_title( '', false );
1597 }
1598 else if( is_day() )
1599 {
1600 $output = __( 'Archive for date:', 'avia_framework' ) . ' ' . get_the_time( __( 'F jS, Y', 'avia_framework' ) );
1601 }
1602 else if( is_month() )
1603 {
1604 $output = __( 'Archive for month:', 'avia_framework' ) . ' ' . get_the_time( __( 'F, Y','avia_framework' ) );
1605 }
1606 else if( is_year() )
1607 {
1608 $output = __( 'Archive for year:','avia_framework' ).' ' . get_the_time( __( 'Y', 'avia_framework' ) );
1609 }
1610 else if( is_search() )
1611 {
1612 global $wp_query;
1613
1614 if( ! empty( $wp_query->found_posts ) )
1615 {
1616 if( $wp_query->found_posts > 1 )
1617 {
1618 $output = $wp_query->found_posts . ' ' . __( 'search results for:', 'avia_framework' ) . ' ' . esc_attr( get_search_query() );
1619 }
1620 else
1621 {
1622 $output = $wp_query->found_posts . ' ' . __( 'search result for:', 'avia_framework' ) . ' ' . esc_attr( get_search_query() );
1623 }
1624 }
1625 else
1626 {
1627 if( ! empty( $_GET['s'] ) )
1628 {
1629 $output = __( 'Search results for:', 'avia_framework') . ' ' . esc_attr( get_search_query() );
1630 }
1631 else
1632 {
1633 $output = __( 'To search the site please enter a valid term', 'avia_framework' );
1634 }
1635 }
1636
1637 }
1638 else if( is_author() )
1639 {
1640 $curauth = ( get_query_var('author_name') ) ? get_user_by('slug', get_query_var( 'author_name' ) ) : get_userdata( get_query_var( 'author' ) );
1641 $output = __( 'Author Archive', 'avia_framework' ) . ' ';
1642
1643 if( isset( $curauth->nickname ) && isset( $curauth->ID ) )
1644 {
1645 $name = apply_filters( 'avf_author_nickname', $curauth->nickname, $curauth->ID );
1646 $output .= __( 'for:', 'avia_framework' ) . ' ' . $name;
1647 }
1648 }
1649 else if( is_tag() )
1650 {
1651 $output = __( 'Tag Archive for:', 'avia_framework' ) . ' ' . single_tag_title( '', false );
1652 }
1653 else if( is_tax() )
1654 {
1655 $term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );
1656 $output = __( 'Archive for:', 'avia_framework' ) . ' ' . $term->name;
1657 }
1658 else
1659 {
1660 $output = __( 'Archives', 'avia_framework' ) . ' ';
1661 }
1662
1663 if( isset( $_GET['paged'] ) && ! empty( $_GET['paged'] ) )
1664 {
1665 // avoid xss vulnerability - e.g. injection of code
1666 $output .= is_numeric( $_GET['paged'] ) ? ' (' . __( 'Page', 'avia_framework' ) . ' ' . $_GET['paged'] . ')' : '';
1667 }
1668
1669 $output = apply_filters( 'avf_which_archive_output', $output );
1670
1671 return $output;
1672 }
1673}
1674
1675
1676if( ! function_exists( 'avia_excerpt' ) )
1677{
1678 /**
1679 * Returns a post excerpt. depending on the order parameter the funciton will try to retrieve the excerpt from a different source
1680 *
1681 * @param int $length
1682 * @param boolean $more_text
1683 * @param array $order
1684 * @return string
1685 */
1686 function avia_excerpt( $length = 250, $more_text = false, $order = array( 'more-tag', 'excerpt' ) )
1687 {
1688 $excerpt = '';
1689
1690 if( $more_text === false )
1691 {
1692 $more_text = __( 'Read more', 'avia_framework' );
1693 }
1694
1695 foreach( $order as $method )
1696 {
1697 if( ! $excerpt )
1698 {
1699 switch( $method )
1700 {
1701 case 'more-tag':
1702 global $more;
1703
1704 $more = 0;
1705 $content = get_the_content( $more_text );
1706 $pos = strpos( $content, 'class="more-link"' );
1707 if( $pos !== false )
1708 {
1709 $excerpt = $content;
1710 }
1711 break;
1712
1713 case 'excerpt' :
1714 $post = get_post( get_the_ID() );
1715 if( $post->post_excerpt )
1716 {
1717 $excerpt = get_the_excerpt();
1718 }
1719 else
1720 {
1721 $excerpt = preg_replace( "!\[.+?\]!", '', get_the_excerpt() );
1722 // $excerpt = preg_replace("!\[.+?\]!", '', $post->post_content);
1723 $excerpt = avia_backend_truncate( $excerpt, $length, ' ' );
1724 }
1725
1726 $excerpt = preg_replace( "!\s\[...\]$!", '...', $excerpt );
1727 break;
1728 }
1729 }
1730 }
1731
1732 if( $excerpt )
1733 {
1734 $excerpt = apply_filters( 'the_content', $excerpt );
1735 $excerpt = str_replace( ']]>', ']]>', $excerpt );
1736 }
1737
1738 return $excerpt;
1739 }
1740}
1741
1742
1743if( ! function_exists( 'avia_get_browser' ) )
1744{
1745 /**
1746 *
1747 * @param string $returnValue
1748 * @param boolean $lowercase
1749 * @return boolean|string|array
1750 */
1751 function avia_get_browser( $returnValue = 'class', $lowercase = false )
1752 {
1753 if( empty( $_SERVER['HTTP_USER_AGENT'] ) )
1754 {
1755 return false;
1756 }
1757
1758 $u_agent = $_SERVER['HTTP_USER_AGENT'];
1759 $bname = 'Unknown';
1760 $platform = 'Unknown';
1761 $ub = 'Unknown';
1762 $version= '';
1763
1764 //First get the platform?
1765 if( preg_match( '!linux!i', $u_agent ) )
1766 {
1767 $platform = 'linux';
1768 }
1769 else if( preg_match( '!macintosh|mac os x!i', $u_agent ) )
1770 {
1771 $platform = 'mac';
1772 }
1773 else if( preg_match( '!windows|win32!i', $u_agent ) )
1774 {
1775 $platform = 'windows';
1776 }
1777
1778 // Next get the name of the useragent yes seperately and for good reason
1779 if( preg_match( '!MSIE!i', $u_agent ) && ! preg_match( '!Opera!i', $u_agent ) )
1780 {
1781 $bname = 'Internet Explorer';
1782 $ub = 'MSIE';
1783 }
1784 else if( preg_match( '!Firefox!i', $u_agent ) )
1785 {
1786 $bname = 'Mozilla Firefox';
1787 $ub = 'Firefox';
1788 }
1789 else if( preg_match( '!Chrome!i', $u_agent ) )
1790 {
1791 $bname = 'Google Chrome';
1792 $ub = 'Chrome';
1793 }
1794 else if( preg_match( '!Safari!i', $u_agent ) )
1795 {
1796 $bname = 'Apple Safari';
1797 $ub = 'Safari';
1798 }
1799 else if( preg_match( '!Opera!i', $u_agent ) )
1800 {
1801 $bname = 'Opera';
1802 $ub = 'Opera';
1803 }
1804 else if( preg_match( '!Netscape!i', $u_agent ) )
1805 {
1806 $bname = 'Netscape';
1807 $ub = 'Netscape';
1808 }
1809
1810 // finally get the correct version number
1811 $known = array( 'Version', $ub, 'other' );
1812
1813 $pattern = '#(?<browser>' . join('|', $known ) . ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
1814 if( ! @preg_match_all( $pattern, $u_agent, $matches ) )
1815 {
1816 // we have no matching number just continue
1817 }
1818
1819 // see how many we have
1820 $i = count( $matches['browser'] );
1821 if( $i != 1 )
1822 {
1823 //we will have two since we are not using 'other' argument yet
1824 //see if version is before or after the name
1825 if( strripos( $u_agent,'Version' ) < strripos( $u_agent, $ub ) )
1826 {
1827 $version = ! empty( $matches['version'][0] ) ? $matches['version'][0] : '';
1828 }
1829 else
1830 {
1831 $version = ! empty( $matches['version'][1] ) ? $matches['version'][1] : '';
1832 }
1833 }
1834 else
1835 {
1836 $version = ! empty( $matches['version'][0] ) ? $matches['version'][0] : '';
1837 }
1838
1839 // check if we have a number
1840 if( $version == null || $version == '' )
1841 {
1842 $version = '?';
1843 }
1844
1845 $mainVersion = $version;
1846 if( strpos( $version, '.' ) !== false )
1847 {
1848 $mainVersion = explode( '.', $version );
1849 $mainVersion = $mainVersion[0];
1850 }
1851
1852 if( $returnValue == 'class' )
1853 {
1854 if( $lowercase )
1855 {
1856 return strtolower( $ub . ' ' . $ub . $mainVersion );
1857 }
1858
1859 return $ub . ' ' . $ub . $mainVersion;
1860 }
1861 else
1862 {
1863 return array(
1864 'userAgent' => $u_agent,
1865 'name' => $bname,
1866 'shortname' => $ub,
1867 'version' => $version,
1868 'mainversion' => $mainVersion,
1869 'platform' => $platform,
1870 'pattern' => $pattern
1871 );
1872 }
1873 }
1874}
1875
1876
1877if( ! function_exists( 'avia_favicon' ) )
1878{
1879 /**
1880 *
1881 * @param string $url
1882 * @return string
1883 */
1884 function avia_favicon( $url = '' )
1885 {
1886 $icon_link = '';
1887 $type = '';
1888
1889 if( $url )
1890 {
1891
1892 if( strpos( $url, '.png' ) !== false )
1893 {
1894 $type = 'image/png';
1895 }
1896 else if( strpos( $url, '.gif' ) !== false )
1897 {
1898 $type = 'image/gif';
1899 }
1900 else
1901 {
1902 $type = 'image/x-icon';
1903 }
1904
1905 $icon_link = '<link rel="icon" href="'.$url.'" type="' . $type . '">';
1906 }
1907
1908 /**
1909 * @param string $icon_link
1910 * @param string $url
1911 * @param string $type
1912 * @return string
1913 */
1914 $icon_link = apply_filters( 'avf_favicon_final_output', $icon_link, $url, $type );
1915
1916 return $icon_link;
1917 }
1918}
1919
1920
1921if( ! function_exists( 'avia_regex' ) )
1922{
1923 /**
1924 * regex for url: http://mathiasbynens.be/demo/url-regex
1925 *
1926 * @param string $string
1927 * @param string|false $pattern
1928 * @param string $start
1929 * @param string $end
1930 * @return false|string
1931 */
1932 function avia_regex( $string, $pattern = false, $start = '^', $end = '' )
1933 {
1934 if( ! $pattern )
1935 {
1936 return false;
1937 }
1938
1939 if( $pattern == 'url' )
1940 {
1941 $pattern = "!$start((https?|ftp)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?)$end!";
1942 }
1943 else if( $pattern == 'mail' )
1944 {
1945 $pattern = "!$start\w[\w|\.|\-]+@\w[\w|\.|\-]+\.[a-zA-Z]{2,4}$end!";
1946 }
1947 else if( $pattern == 'image' )
1948 {
1949 $pattern = "!$start(https?(?://([^/?#]*))?([^?#]*?\.(?:jpg|gif|png)))$end!";
1950 }
1951 else if( strpos( $pattern, '<' ) === 0 )
1952 {
1953 $pattern = str_replace( '<', '',$pattern );
1954 $pattern = str_replace( '>', '',$pattern );
1955
1956 if( strpos( $pattern, '/' ) !== 0 )
1957 {
1958 $close = "\/>";
1959 $pattern = str_replace( '/', '', $pattern );
1960 }
1961
1962 $pattern = trim( $pattern );
1963 if( ! isset( $close ) )
1964 {
1965 $close = "<\/" . $pattern . ">";
1966 }
1967
1968 $pattern = "!$start\<$pattern.+?$close!";
1969 }
1970
1971 $result = array();
1972 preg_match( $pattern, $string, $result );
1973
1974 if( empty( $result[0] ) )
1975 {
1976 return false;
1977 }
1978
1979 return $result;
1980 }
1981}
1982
1983
1984if( ! function_exists( 'avia_debugging_info' ) )
1985{
1986 function avia_debugging_info()
1987 {
1988 if ( is_feed() )
1989 {
1990 return;
1991 }
1992
1993 $theme = wp_get_theme();
1994 $child = '';
1995
1996 if( is_child_theme() )
1997 {
1998 $child = "- - - - - - - - - - -\n";
1999 $child .= 'ChildTheme: ' . $theme->get( 'Name' ) . "\n";
2000 $child .= 'ChildTheme Version: ' . $theme->get( 'Version' ) . "\n";
2001 $child .= 'ChildTheme Installed: ' . $theme->get( 'Template' ) . "\n\n";
2002 $child .= "- - - - - - - - - - -\n";
2003
2004 $theme = wp_get_theme( $theme->get( 'Template' ) );
2005 }
2006
2007 $info = "\n\n<!--\n";
2008 $info .= "Debugging Info for Theme support: \n\n";
2009 $info .= 'Theme: ' . $theme->get( 'Name' ) . "\n";
2010 $info .= 'Version: ' . $theme->get( 'Version' ) . "\n";
2011 $info .= 'Installed: ' . $theme->get_template() . "\n";
2012 $info .= 'AviaFramework Version: ' . AV_FRAMEWORK_VERSION . "\n";
2013
2014
2015 if( class_exists( 'AviaBuilder', false ) )
2016 {
2017 $info .= 'AviaBuilder Version: ' . AviaBuilder::VERSION . "\n";
2018
2019 if( class_exists( 'aviaElementManager', false ) )
2020 {
2021 $info .= 'aviaElementManager Version: ' . aviaElementManager::VERSION . "\n";
2022 $update_state = get_option( 'av_alb_element_mgr_update', '' );
2023 if( '' != $update_state )
2024 {
2025 $info .= "aviaElementManager update state: in update \n";
2026 }
2027 }
2028 }
2029
2030
2031 $info .= $child;
2032
2033 //memory setting, peak usage and number of active plugins
2034 $info .= 'ML:' . trim( @ini_get( 'memory_limit' ) ,'M' ) . '-PU:' . ( ceil (memory_get_peak_usage() / 1000 / 1000 ) ) . '-PLA:' . avia_count_active_plugins() . "\n";
2035 $info .= 'WP:' . get_bloginfo( 'version' ) . "\n";
2036
2037 $comp_levels = array(
2038 'none' => 'disabled',
2039 'avia-module' => 'modules only',
2040 'avia' => 'all theme files',
2041 'all' => 'all files',
2042 'minified_only' => 'load minified only'
2043 );
2044
2045 $info .= 'Compress: CSS:' . $comp_levels[ avia_get_option( 'merge_css', 'avia-module' ) ] . ' - JS:' . $comp_levels[ avia_get_option( 'merge_js', 'avia-module' ) ] . "\n";
2046
2047 $token = trim( avia_get_option( 'updates_envato_token' ) );
2048 $username = avia_get_option( 'updates_username' );
2049 $API = avia_get_option( 'updates_api_key' );
2050
2051 $updates = 'disabled';
2052
2053 if( ! empty( $token ) )
2054 {
2055 $token_state = trim( avia_get_option( 'updates_envato_token_state' ) );
2056 $verified_token = trim( avia_get_option( 'updates_envato_verified_token' ) );
2057
2058 if( empty( $token_state ) )
2059 {
2060 $updates = 'enabled - unverified Envato token';
2061 }
2062 else
2063 {
2064 $updates = $token_state == $verified_token ? 'enabled - verified token' : 'enabled - token has changed and not verified';
2065 }
2066 }
2067 else if( $username && $API )
2068 {
2069 $updates = 'enabled';
2070 if( isset( $_GET['username'] ) )
2071 {
2072 $updates .= " ({$username})";
2073 }
2074
2075 $updates .= ' - deprecated Envato API - register Envato Token';
2076 }
2077
2078 $info .= 'Updates: ' . $updates . "\n";
2079
2080 /**
2081 *
2082 * @used_by enfold\includes\helper-assets.php av_untested_plugins_debugging_info() 10
2083 * @param string
2084 * @return string
2085 */
2086 $info = apply_filters( 'avf_debugging_info_add', $info );
2087
2088 $info .= '-->';
2089
2090 echo apply_filters( 'avf_debugging_info', $info );
2091 }
2092
2093 add_action( 'wp_head', 'avia_debugging_info', 9999999 );
2094 add_action( 'admin_print_scripts', 'avia_debugging_info', 9999999 );
2095}
2096
2097
2098if( ! function_exists( 'avia_count_active_plugins' ) )
2099{
2100 function avia_count_active_plugins()
2101 {
2102 $plugins = count( get_option( 'active_plugins', array() ) );
2103
2104 if( is_multisite() && function_exists( 'get_site_option' ) )
2105 {
2106 $plugins += count( get_site_option( 'active_sitewide_plugins', array() ) );
2107 }
2108
2109 return $plugins;
2110 }
2111}
2112
2113
2114if( ! function_exists( 'avia_clean_string' ) )
2115{
2116 /**
2117 *
2118 * @param string $string
2119 * @return string
2120 */
2121 function avia_clean_string( $string )
2122 {
2123 $string = str_replace( ' ', '_', $string ); // Replaces all spaces with underscores.
2124 $string = preg_replace( '/[^A-Za-z0-9\-]/', '', $string ); // Removes special chars.
2125
2126 return preg_replace( '/-+/', '-', strtolower( $string ) ); // Replaces multiple hyphens with single one.
2127 }
2128}
2129
2130
2131if( ! function_exists('kriesi_backlink' ) )
2132{
2133 /**
2134 *
2135 * @param boolean $frontpage_only
2136 * @param string|false $theme_name_passed
2137 * @return string
2138 */
2139 function kriesi_backlink( $frontpage_only = false, $theme_name_passed = false )
2140 {
2141 $no = '';
2142 $theme_string = '';
2143 $theme_name = $theme_name_passed ? $theme_name_passed : THEMENAME;
2144
2145 $random_number = get_option( THEMENAMECLEAN . '_fixed_random' );
2146
2147 $check = $random_number % 3;
2148
2149 switch( $check )
2150 {
2151 case 0:
2152 $theme_string = $theme_name . ' Theme by Kriesi';
2153 break;
2154 case 1:
2155 $theme_string = $theme_name . ' WordPress Theme by Kriesi';
2156 break;
2157 case 2:
2158 default:
2159 $theme_string = 'powered by ' . $theme_name . ' WordPress Theme';
2160 break;
2161 }
2162
2163 if( ! empty( $frontpage_only ) && ! is_front_page() )
2164 {
2165 $no = "rel='nofollow'";
2166 }
2167
2168 $link = " - <a {$no} href='https://kriesi.at'>{$theme_string}</a>";
2169
2170 /**
2171 * @param string $link
2172 * @return string
2173 */
2174 $link = apply_filters( 'kriesi_backlink', $link );
2175
2176 return $link;
2177 }
2178}
2179
2180
2181if( ! function_exists( 'avia_header_class_filter' ) )
2182{
2183 /**
2184 *
2185 * @param string $default
2186 * @return string
2187 */
2188 function avia_header_class_filter( $default = '' )
2189 {
2190 $default = apply_filters( 'avia_header_class_filter', $default );
2191 return $default;
2192 }
2193}
2194
2195
2196if( ! function_exists( 'avia_theme_version_higher_than' ) )
2197{
2198 /**
2199 * Checks for parent theme version >= a given version
2200 *
2201 * @since < 4.0
2202 * @param string $check_for_version
2203 * @return boolean
2204 */
2205 function avia_theme_version_higher_than( $check_for_version = '' )
2206 {
2207 $theme_version = avia_get_theme_version();
2208
2209 if( version_compare( $theme_version, $check_for_version , '>=' ) )
2210 {
2211 return true;
2212 }
2213
2214 return false;
2215 }
2216}
2217
2218if( ! function_exists( 'avia_enqueue_style_conditionally' ) )
2219{
2220 /**
2221 * Enque a css file, based on theme options or other conditions that get passed and must be evaluated as true
2222 *
2223 * params are the same as in enque style, only the condition is first: https://core.trac.wordpress.org/browser/tags/4.9/src/wp-includes/functions.wp-styles.php#L164
2224 *
2225 * @since 4.3
2226 * @added_by Kriesi
2227 * @param boolean $condition
2228 * @param string $handle
2229 * @param string $src
2230 * @param array $deps
2231 * @param boolean|string $ver
2232 * @param string $media
2233 * @param boolean $deregister
2234 * @return void
2235 */
2236 function avia_enqueue_style_conditionally( $condition = false, $handle = '', $src = '', $deps = array(), $ver = false, $media = 'all', $deregister = true )
2237 {
2238 if( $condition == false )
2239 {
2240 if( $deregister )
2241 {
2242 wp_deregister_style( $handle );
2243 }
2244
2245 return;
2246 }
2247
2248 wp_enqueue_style( $handle, $src, $deps, $ver, $media );
2249 }
2250}
2251
2252
2253if( ! function_exists( 'avia_enqueue_script_conditionally' ) )
2254{
2255 /**
2256 * Enque a js file, based on theme options or other conditions that get passed and must be evaluated as true
2257 *
2258 * params are the same as in enque style, only the condition is first: https://core.trac.wordpress.org/browser/tags/4.9/src/wp-includes/functions.wp-scripts.php#L264
2259 *
2260 * @since 4.3
2261 * @added_by Kriesi
2262 * @param boolean $condition
2263 * @param string $handle
2264 * @param string $src
2265 * @param array $deps
2266 * @param boolean|string $ver
2267 * @param boolean $in_footer
2268 * @param boolean $deregister
2269 * @return void
2270 */
2271 function avia_enqueue_script_conditionally( $condition = false, $handle = '', $src = '', $deps = array(), $ver = false, $in_footer = false, $deregister = true )
2272 {
2273 if( $condition == false )
2274 {
2275 if( $deregister )
2276 {
2277 wp_deregister_script( $handle );
2278 }
2279
2280 return;
2281 }
2282
2283 wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer );
2284 }
2285}
2286
2287
2288if( ! function_exists( 'avia_disable_query_migrate' ) )
2289{
2290 /**
2291 * Makes sure that jquery no longer depends on jquery migrate.
2292 *
2293 * @since 4.3
2294 * @added_by Kriesi
2295 * @param array $condition
2296 * @return array
2297 */
2298 function avia_disable_query_migrate()
2299 {
2300 global $wp_scripts;
2301
2302 if( ! is_admin() )
2303 {
2304 if( isset( $wp_scripts->registered['jquery'] ) )
2305 {
2306 foreach( $wp_scripts->registered['jquery']->deps as $key => $dep )
2307 {
2308 if( $dep == 'jquery-migrate' )
2309 {
2310 unset( $wp_scripts->registered['jquery']->deps[ $key ] );
2311 }
2312 }
2313 }
2314 }
2315 }
2316}
2317
2318
2319if( ! function_exists( 'avia_get_submenu_count' ) )
2320{
2321 /**
2322 * Counts the number of submenu items of a menu
2323 *
2324 * @since 4.3
2325 * @added_by Kriesi
2326 * @param array $location
2327 * @return int $count
2328 */
2329 function avia_get_submenu_count( $location )
2330 {
2331 $menus = get_nav_menu_locations();
2332 $count = 0;
2333
2334 if( ! isset( $menus[ $location ] ) )
2335 {
2336 return $count;
2337 }
2338
2339 $items = wp_get_nav_menu_items( $menus[ $location ] );
2340
2341 //if no menu is set we dont know if the fallback menu will generate submenu items so we assume thats true
2342 if( ! $items )
2343 {
2344 return 1;
2345 }
2346
2347 foreach( $items as $item )
2348 {
2349 if( isset( $item->menu_item_parent ) && $item->menu_item_parent > 0 )
2350 {
2351 $count++;
2352 }
2353 }
2354
2355 return $count;
2356 }
2357}
2358
2359
2360if( ! function_exists( 'avia_get_active_widget_count' ) )
2361{
2362 /**
2363 * Counts the number of active widget areas (widget areas that got a widget inside them are considered active)
2364 *
2365 * @since 4.3
2366 * @added_by Kriesi
2367 * @return int $count
2368 */
2369 function avia_get_active_widget_count()
2370 {
2371 global $_wp_sidebars_widgets;
2372
2373 $count = 0;
2374
2375 foreach( $_wp_sidebars_widgets as $widget_area => $widgets )
2376 {
2377 if( $widget_area == 'wp_inactive_widgets' || $widget_area == 'array_version' )
2378 {
2379 continue;
2380 }
2381
2382 if( ! empty( $widgets ) )
2383 {
2384 $count++;
2385 }
2386 }
2387
2388 return $count;
2389 }
2390}
2391
2392
2393if( ! function_exists( 'avia_get_theme_version' ) )
2394{
2395 /**
2396 * Helper function that returns the (parent) theme version number to be added to scipts and css links
2397 *
2398 * @since 4.3.2
2399 * @added_by Günter
2400 * @return string
2401 */
2402 function avia_get_theme_version( $which = 'parent' )
2403 {
2404 $theme = wp_get_theme();
2405 if( false !== $theme->parent() && ( 'parent' == $which ) )
2406 {
2407 $theme = $theme->parent();
2408 }
2409 $vn = $theme->get( 'Version' );
2410
2411 return $vn;
2412 }
2413}
2414
2415
2416if( ! function_exists( 'handler_wp_targeted_link_rel' ) )
2417{
2418 /**
2419 * Eliminates rel noreferrer and noopener from links that are not cross origin.
2420 *
2421 * @since 4.6.3
2422 * @added_by Günter
2423 * @param string $rel 'noopener noreferrer'
2424 * @param string $link_html space separated string of a attributes
2425 * @return string
2426 */
2427 function handler_wp_targeted_link_rel( $rel, $link_html )
2428 {
2429 $url = get_bloginfo( 'url' );
2430 $url = str_ireplace( array( 'http://', 'https://' ), '', $url );
2431
2432 $href = '';
2433 $found = preg_match( '/href=["\']?([^"\'>]+)["\']?/', $link_html, $href );
2434 if( empty( $found ) )
2435 {
2436 return $rel;
2437 }
2438
2439 $info = explode( '?', $href[1] );
2440
2441 if( false !== stripos( $info[0], $url ) )
2442 {
2443 return '';
2444 }
2445
2446 return $rel;
2447 }
2448
2449 add_filter( 'wp_targeted_link_rel', 'handler_wp_targeted_link_rel', 10, 2 );
2450}
2451
2452
2453if( ! function_exists( 'handler_wp_walker_nav_menu_start_el' ) )
2454{
2455 /**
2456 * Apply security fix for external links
2457 *
2458 * @since 4.6.3
2459 * @added_by Günter
2460 * @param string $item_output The menu item's starting HTML output.
2461 * @param WP_Post|mixed $item Menu item data object.
2462 * @param int $depth Depth of menu item. Used for padding.
2463 * @param stdClass $args An object of wp_nav_menu() arguments.
2464 * @return type
2465 */
2466 function handler_wp_walker_nav_menu_start_el( $item_output, $item, $depth, $args )
2467 {
2468 $item_output = avia_targeted_link_rel( $item_output );
2469
2470 return $item_output;
2471 }
2472
2473 add_filter( 'walker_nav_menu_start_el', 'handler_wp_walker_nav_menu_start_el', 10, 4 );
2474}
2475
2476
2477if( ! function_exists( 'avia_targeted_link_rel' ) )
2478{
2479 /**
2480 * Wrapper function for backwards comp. with older WP vrsions
2481 *
2482 * @since 4.6.3
2483 * @uses wp_targeted_link_rel @since 5.1.0
2484 * @uses handler_wp_targeted_link_rel filter wp_targeted_link_rel
2485 * @added_by Günter
2486 * @param string $text
2487 * @param true|string $exec_call true | 'translate' | 'reverse'
2488 * @return string
2489 */
2490 function avia_targeted_link_rel( $text, $exec_call = true )
2491 {
2492 /**
2493 * For older WP versions we skip this feature
2494 */
2495 if( ! function_exists( 'wp_targeted_link_rel' ) )
2496 {
2497 return $text;
2498 }
2499
2500 global $wp_version;
2501
2502 /**
2503 * WP changed the way it splits the attributes. '_' is not supported as a valid attribute and removes these attributes.
2504 * See wp-includes\kses.php wp_kses_hair( $attr, $allowed_protocols );
2505 * This breaks our data-xxx attributes like data-av_icon.
2506 *
2507 * This might change in a future version of WP.
2508 */
2509 if( version_compare( $wp_version, '5.3.1', '<' ) )
2510 {
2511 return true === $exec_call ? wp_targeted_link_rel( $text ) : $text;
2512 }
2513
2514 /**
2515 * Do not run (more expensive) regex if no links with targets
2516 */
2517 if( stripos( $text, 'target' ) === false || stripos( $text, '<a ' ) === false || is_serialized( $text ) )
2518 {
2519 return $text;
2520 }
2521
2522 $attr_translate = array(
2523 'data-av_icon',
2524 'data-av_iconfont',
2525 'data-fbscript_id'
2526 );
2527
2528 /**
2529 * Add more custom attributes that are removed by WP
2530 *
2531 * @since 4.6.4
2532 * @param array
2533 * @retrun array
2534 */
2535 $attr_translate = apply_filters( 'avf_translate_targeted_link_rel_attributes', $attr_translate );
2536
2537 $trans_attributes = array();
2538 foreach( $attr_translate as $value )
2539 {
2540 $trans_attributes[] = str_replace( '_', '----', $value);
2541 }
2542
2543 // Fallback - this might break page, but version is already outdated
2544 if( version_compare( phpversion(), '5.3', '<' ) )
2545 {
2546 $text_trans = str_replace( $attr_translate, $trans_attributes, $text );
2547 $text_trans = wp_targeted_link_rel( $text_trans );
2548 return str_replace( $trans_attributes, $attr_translate, $text_trans );
2549 }
2550
2551 /**
2552 * To avoid breaking a page we do not replace the the attribute names with simple str_replace but
2553 * use the same way WP does to filter the a tags for replacing
2554 *
2555 * see wp-includes\formatting.php
2556 */
2557 $script_and_style_regex = '/<(script|style).*?<\/\\1>/si';
2558
2559 $test_exec = true === $exec_call ? 'true' : $exec_call;
2560 switch( $test_exec )
2561 {
2562 case 'reverse':
2563 $start = 1;
2564 break;
2565 case 'translate':
2566 case 'true':
2567 default:
2568 $start = 0;
2569 break;
2570 }
2571
2572 for( $iteration = $start; $iteration < 2; $iteration++ )
2573 {
2574 $matches = array();
2575 preg_match_all( $script_and_style_regex, $text, $matches );
2576 $extra_parts = $matches[0];
2577 $html_parts = preg_split( $script_and_style_regex, $text );
2578
2579 switch( $iteration )
2580 {
2581 case 0;
2582 $source = $attr_translate;
2583 $replace = $trans_attributes;
2584 break;
2585 case 1:
2586 default:
2587 $source = $trans_attributes;
2588 $replace = $attr_translate;
2589 break;
2590 }
2591
2592 foreach ( $html_parts as &$part )
2593 {
2594 $part = preg_replace_callback( '|<a\s([^>]*target\s*=[^>]*)>|i', function ( $matches ) use( $source, $replace )
2595 {
2596 $link_html = $matches[1];
2597
2598 // Consider the html escaped if there are no unescaped quotes
2599 $is_escaped = ! preg_match( '/(^|[^\\\\])[\'"]/', $link_html );
2600 if ( $is_escaped )
2601 {
2602 // Replace only the quotes so that they are parsable by wp_kses_hair, leave the rest as is
2603 $link_html = preg_replace( '/\\\\([\'"])/', '$1', $link_html );
2604 }
2605
2606 foreach( $source as $key => $value )
2607 {
2608 $link_html = preg_replace( '|' . $value . '\s*=|i', $replace[ $key ] . '=', $link_html );
2609 }
2610
2611 if ( $is_escaped )
2612 {
2613 $link_html = preg_replace( '/[\'"]/', '\\\\$0', $link_html );
2614 }
2615
2616 return "<a {$link_html}>";
2617
2618 }, $part );
2619 }
2620
2621 unset( $part );
2622
2623 $text = '';
2624 for( $i = 0; $i < count( $html_parts ); $i++ )
2625 {
2626 $text .= $html_parts[ $i ];
2627 if( isset( $extra_parts[ $i ] ) )
2628 {
2629 $text .= $extra_parts[ $i ];
2630 }
2631 }
2632
2633 switch( $iteration )
2634 {
2635 case 0;
2636 if( true === $exec_call )
2637 {
2638 $text = wp_targeted_link_rel( $text );
2639 }
2640 break;
2641 default:
2642 break;
2643 }
2644
2645 if( 'translate' == $test_exec )
2646 {
2647 break;
2648 }
2649 }
2650
2651 return $text;
2652 }
2653}
2654
2655
2656if( ! function_exists( 'handler_avia_widget_text' ) )
2657{
2658 /**
2659 * Replace attributes with _ that wp_targeted_link_rel() does not remove them
2660 *
2661 * @since 4.6.4
2662 * @param string $content
2663 * @param array $instance
2664 * @param WP_Widget $widget
2665 * @return type
2666 */
2667 function handler_avia_widget_text( $content = '', $instance = null, $widget = null )
2668 {
2669 /**
2670 * To support WP_Widget_Text:
2671 *
2672 * - Needs js code to replace translated attributes in frontend as this widget has no filter after call to wp_targeted_link_rel()
2673 * or
2674 * - Add a filter to wp-includes\widgets\class-wp-widget-text.php after wp_targeted_link_rel() call
2675 */
2676 if( ! $widget instanceof WP_Widget_Custom_HTML || ! is_string( $content ) )
2677 {
2678 return $content;
2679 }
2680
2681 return avia_targeted_link_rel( $content, 'translate' );
2682 }
2683
2684 add_filter( 'widget_text', 'handler_avia_widget_text', 90000, 3 );
2685}
2686
2687
2688if( ! function_exists( 'handler_avia_widget_custom_html_content' ) )
2689{
2690 /**
2691 * Revert changes to attributes with _
2692 *
2693 * @since 4.6.4
2694 * @param string $content
2695 * @param array $instance
2696 * @param WP_Widget $widget
2697 * @return string
2698 */
2699 function handler_avia_widget_custom_html_content( $content = '', $instance = null, $widget = null )
2700 {
2701 if( ! is_string( $content ) )
2702 {
2703 return $content;
2704 }
2705
2706 return avia_targeted_link_rel( $content, 'reverse' );
2707 }
2708
2709 add_filter( 'widget_custom_html_content', 'handler_avia_widget_custom_html_content', 90000, 3 );
2710}
2711
2712
2713if( ! function_exists( 'avia_accessibility_body_class' ) )
2714{
2715 /**
2716 * Add accessibility conformance classes to body to alter stylings without breaking existing sites
2717 * e.g. line-height is required to be larger than in theme settings
2718 *
2719 * @since 4.8.8
2720 * @param array $classes
2721 * @return array
2722 */
2723 function avia_accessibility_body_class( array $classes )
2724 {
2725 switch( avia_get_option( 'accessibility_conformance_option' ) )
2726 {
2727 case 'a_level':
2728 $classes[] = 'av-accessibility-a';
2729 break;
2730 case 'aa_level':
2731 $classes[] = 'av-accessibility-a av-accessibility-aa';
2732 break;
2733 case 'aaa_level':
2734 $classes[] = 'av-accessibility-a av-accessibility-aa av-accessibility-aaa';
2735 break;
2736 }
2737
2738 return $classes;
2739 }
2740
2741 add_filter( 'body_class', 'avia_accessibility_body_class' );
2742}
2743
2744
2745
2746if( ! function_exists( 'avia_post_swipe_body_class' ) )
2747{
2748 /**
2749 * Swipe feature for post navigation.
2750 *
2751 * @since 5.5
2752 * @param array $classes
2753 * @return array
2754 */
2755 function avia_post_swipe_body_class( array $classes )
2756 {
2757 global $post;
2758
2759 if( ! is_single() )
2760 {
2761 return $classes;
2762 }
2763
2764 /**
2765 * Allows to disable swipe for certain post types
2766 *
2767 * @since 5.5
2768 * @param string $swipe_option
2769 * @param WP_Post $post
2770 * @return string 'post_nav_swipe' | ''
2771 */
2772 $swipe = apply_filters( 'avf_post_nav_swipe_support', avia_get_option( 'post_nav_swipe' ), $post );
2773
2774 if( 'post_nav_swipe' == $swipe )
2775 {
2776 $classes[] = 'avia-post-nav-swipe-enabled';
2777 }
2778
2779 return $classes;
2780 }
2781
2782 add_filter( 'body_class', 'avia_post_swipe_body_class' );
2783}
2784