';
$svg .= ' ';
$svg .= '';
return $svg;
}
}
/*
Truncate Function
======================================= */
if ( ! function_exists( 'evolve_truncate' ) ) {
function evolve_truncate( $maxLength, $html, $isUtf8 = true, $trailing = '...' ) {
$printedLength = 0;
$position = 0;
$tags = array();
// For UTF-8, we need to count multibyte sequences as one character.
$re = $isUtf8
? '{?([a-z]+)[^>]*>|?[a-zA-Z0-9]+;|[\x80-\xFF][\x80-\xBF]*}'
: '{?([a-z]+)[^>]*>|?[a-zA-Z0-9]+;}';
while ( $printedLength < $maxLength && preg_match( $re, $html, $match, PREG_OFFSET_CAPTURE, $position ) ) {
list( $tag, $tagPosition ) = $match[0];
// Print text leading up to the tag.
$str = substr( $html, $position, $tagPosition - $position );
if ( $printedLength + strlen( $str ) > $maxLength ) {
print( substr( $str, 0, $maxLength - $printedLength ) );
$printedLength = $maxLength;
break;
}
print( $str );
$printedLength += strlen( $str );
if ( $printedLength >= $maxLength ) {
break;
}
if ( $tag[0] == '&' || ord( $tag ) >= 0x80 ) {
// Pass the entity or UTF-8 multibyte sequence through unchanged.
print( $tag );
$printedLength ++;
} else {
// Handle the tag.
$tagName = $match[1][0];
if ( $tag[1] == '/' ) {
// This is a closing tag.
$openingTag = array_pop( $tags );
assert( $openingTag == $tagName ); // check that tags are properly nested.
print( $tag );
} else if ( $tag[ strlen( $tag ) - 2 ] == '/' ) {
// Self-closing tag.
print( $tag );
} else {
// Opening tag.
print( $tag );
$tags[] = $tagName;
}
}
// Continue after the tag.
$position = $tagPosition + strlen( $tag );
}
// Print any remaining text.
if ( $printedLength < $maxLength && $position < strlen( $html ) ) {
print( substr( $html, $position, $maxLength - $printedLength ) );
}
// Print Trailing
if ( ( ( ( $maxLength - $printedLength ) == $maxLength || ( $maxLength - $printedLength ) == 0 ) && $position == 0 && strlen( $html ) > $maxLength ) ) {
print $trailing;
}
// Close any open tags.
while ( ! empty( $tags ) ) {
printf( '%s>', array_pop( $tags ) );
}
}
}
/*
Custom Excerpt Length
======================================= */
if ( ! function_exists( 'evolve_excerpt_max_charlength' ) ) {
function evolve_excerpt_max_charlength( $limit ) {
return wp_trim_words( get_the_excerpt(), $limit );
}
}
/*
Get First Image
======================================= */
if ( ! function_exists( 'evolve_get_first_image' ) ) {
function evolve_get_first_image() {
global $post;
if ( evolve_theme_mod( 'evl_featured_images', '1' ) != "1" ) {
return;
}
$first_img = '';
preg_match_all( '//i', $post->post_content, $matches );
if ( isset( $matches[1][0] ) ) {
$first_img = $matches [1][0];
}
return $first_img;
}
}
/*
Tiny URL
======================================= */
if ( ! function_exists( 'evolve_tinyurl' ) ) {
function evolve_tinyurl( $url ) {
$response = esc_url( wp_remote_retrieve_body( wp_remote_get( 'http://tinyurl.com/api-create.php?url=' . $url ) ) );
return $response;
}
}
/*
Function To Change The HEX Color Code
======================================= */
if ( ! function_exists( 'evolve_hex_change' ) ) {
function evolve_hex_change( $hex, $steps = '-12' ) {
// Steps should be between -255 and 255. Negative = darker, positive = lighter
$steps = max( - 255, min( 255, $steps ) );
// Normalize into a six character long hex string
$hex = str_replace( '#', '', $hex );
if ( strlen( $hex ) == 3 ) {
$hex = str_repeat( substr( $hex, 0, 1 ), 2 ) . str_repeat( substr( $hex, 1, 1 ), 2 ) . str_repeat( substr( $hex, 2, 1 ), 2 );
}
// Split into three parts: R, G and B
$color_parts = str_split( $hex, 2 );
$return = '#';
foreach ( $color_parts as $color ) {
$color = hexdec( $color ); // Convert to decimal
$color = max( 0, min( 255, $color + $steps ) ); // Adjust color
$return .= str_pad( dechex( $color ), 2, '0', STR_PAD_LEFT ); // Make two char hex code
}
return $return;
}
}
/*
Convert HEX Color Code To RGB(a) With Alpha
======================================= */
if ( ! function_exists( 'evolve_hex_rgba' ) ) {
function evolve_hex_rgba( $hex, $alpha = false ) {
$hex = str_replace( '#', '', $hex );
$length = strlen( $hex );
$rgb['r'] = hexdec( $length == 6 ? substr( $hex, 0, 2 ) : ( $length == 3 ? str_repeat( substr( $hex, 0, 1 ), 2 ) : 0 ) );
$rgb['g'] = hexdec( $length == 6 ? substr( $hex, 2, 2 ) : ( $length == 3 ? str_repeat( substr( $hex, 1, 1 ), 2 ) : 0 ) );
$rgb['b'] = hexdec( $length == 6 ? substr( $hex, 4, 2 ) : ( $length == 3 ? str_repeat( substr( $hex, 2, 1 ), 2 ) : 0 ) );
if ( $alpha ) {
$rgb['a'] = $alpha;
}
return implode( array_keys( $rgb ) ) . '(' . implode( ', ', $rgb ) . ')';
}
}
/*
Custom Menu Walker
======================================= */
if ( ! class_exists( 'evolve_custom_menu_walker' ) ) {
/**
* WP_Bootstrap_Navwalker class.
*
* @extends Walker_Nav_Menu
*/
class evolve_custom_menu_walker extends Walker_Nav_Menu {
/**
* Starts the list before the elements are added.
*
* @since WP 3.0.0
*
* @see Walker_Nav_Menu::start_lvl()
*
* @param string $output Used to append additional content (passed by reference).
* @param int $depth Depth of menu item. Used for padding.
* @param stdClass $args An object of wp_nav_menu() arguments.
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = str_repeat( $t, $depth );
// Default class to add to the file.
$classes = array( 'dropdown-menu' );
/**
* Filters the CSS class(es) applied to a menu list element.
*
* @since WP 4.8.0
*
* @param array $classes The CSS classes that are applied to the menu `` element.
* @param stdClass $args An object of `wp_nav_menu()` arguments.
* @param int $depth Depth of menu item. Used for padding.
*/
$class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
/**
* The `.dropdown-menu` container needs to have a labelledby
* attribute which points to it's trigger link.
*
* Form a string for the labelledby attribute from the the latest
* link with an id that was added to the $output.
*/
$labelledby = '';
// find all links with an id in the output.
preg_match_all( '/(/im', $output, $matches );
// with pointer at end of array check if we got an ID match.
if ( end( $matches[2] ) ) {
// build a string to use as aria-labelledby.
$labelledby = 'aria-labelledby="' . end( $matches[2] ) . '"';
}
$output .= "{$n}{$indent}{$n}";
}
/**
* Starts the element output.
*
* @since WP 3.0.0
* @since WP 4.4.0 The {@see 'nav_menu_item_args'} filter was added.
*
* @see Walker_Nav_Menu::start_el()
*
* @param string $output Used to append additional content (passed by reference).
* @param WP_Post $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @param stdClass $args An object of wp_nav_menu() arguments.
* @param int $id Current item ID.
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
$t = '';
$n = '';
} else {
$t = "\t";
$n = "\n";
}
$indent = ( $depth ) ? str_repeat( $t, $depth ) : '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
// Initialize some holder variables to store specially handled item
// wrappers and icons.
$linkmod_classes = array();
$icon_classes = array();
/**
* Get an updated $classes array without linkmod or icon classes.
*
* NOTE: linkmod and icon class arrays are passed by reference and
* are maybe modified before being used later in this function.
*/
$classes = self::seporate_linkmods_and_icons_from_classes( $classes, $linkmod_classes, $icon_classes, $depth );
// Join any icon classes plucked from $classes into a string.
$icon_class_string = join( ' ', $icon_classes );
/**
* Filters the arguments for a single nav menu item.
*
* WP 4.4.0
*
* @param stdClass $args An object of wp_nav_menu() arguments.
* @param WP_Post $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
*/
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
// Add .dropdown or .active classes where they are needed.
if ( isset( $args->has_children ) && $args->has_children ) {
$classes[] = 'dropdown';
}
if ( in_array( 'current-menu-item', $classes, true ) || in_array( 'current-menu-parent', $classes, true ) ) {
$classes[] = 'active';
}
// Add some additional default classes to the item.
$classes[] = 'menu-item-' . $item->ID;
$classes[] = 'nav-item';
// Allow filtering the classes.
$classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth );
// Form a string of classes in format: class="class_names".
$class_names = join( ' ', $classes );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
/**
* Filters the ID applied to a menu item's list item element.
*
* @since WP 3.0.1
* @since WP 4.1.0 The `$depth` parameter was added.
*
* @param string $menu_id The ID that is applied to the menu item's `- ` element.
* @param WP_Post $item The current menu item.
* @param stdClass $args An object of wp_nav_menu() arguments.
* @param int $depth Depth of menu item. Used for padding.
*/
$id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '
- ';
// initialize array for holding the $atts for the link item.
$atts = array();
// Set title from item to the $atts array - if title is empty then
// default to item title.
if ( empty( $item->attr_title ) ) {
$atts['title'] = ! empty( $item->title ) ? strip_tags( $item->title ) : '';
} else {
$atts['title'] = $item->attr_title;
}
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
// If item has_children add atts to .
if ( isset( $args->has_children ) && $args->has_children && $args->depth > 1 ) {
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts['data-hover'] = 'dropdown';
$atts['data-toggle'] = 'dropdown';
$atts['aria-haspopup'] = 'true';
$atts['aria-expanded'] = 'false';
$atts['class'] = 'dropdown-toggle nav-link';
$atts['id'] = 'menu-item-dropdown-' . $item->ID;
} else {
$atts['href'] = ! empty( $item->url ) ? $item->url : '#';
// Items in dropdowns use .dropdown-item instead of .nav-link.
if ( $depth > 0 ) {
$atts['class'] = 'dropdown-item';
} else {
$atts['class'] = 'nav-link';
}
}
// update atts of this item based on any custom linkmod classes.
$atts = self::update_atts_for_linkmod_type( $atts, $linkmod_classes );
// Allow filtering of the $atts array before using it.
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
// Build a string of html containing all the atts for the item.
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
/**
* Set a typeflag to easily test if this is a linkmod or not.
*/
$linkmod_type = self::get_linkmod_type( $linkmod_classes );
/**
* START appending the internal item contents to the output.
*/
$item_output = isset( $args->before ) ? $args->before : '';
/**
* This is the start of the internal nav item. Depending on what
* kind of linkmod we have we may need different wrapper elements.
*/
if ( '' !== $linkmod_type ) {
// is linkmod, output the required element opener.
$item_output .= self::linkmod_element_open( $linkmod_type, $attributes );
} else {
// With no link mod type set this must be a standard tag.
if ( evolve_theme_mod( 'evl_main_menu_hover_effect', 'rollover' ) == "disable" || strpos( $class_names, 'menu-item-language' ) == true ) {
$item_output .= '';
} else {
$item_output .= '';
}
}
/**
* Initiate empty icon var, then if we have a string containing any
* icon classes form the icon markup with an element. This is
* output inside of the item before the $title (the link text).
*/
$icon_html = '';
if ( ! empty( $icon_class_string ) ) {
// append an with the icon classes to what is output before links.
$icon_html = ' ';
}
/** This filter is documented in wp-includes/post-template.php */
$title = apply_filters( 'the_title', $item->title, $item->ID );
/**
* Filters a menu item's title.
*
* @since WP 4.4.0
*
* @param string $title The menu item's title.
* @param WP_Post $item The current menu item.
* @param stdClass $args An object of wp_nav_menu() arguments.
* @param int $depth Depth of menu item. Used for padding.
*/
$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
/**
* If the .sr-only class was set apply to the nav items text only.
*/
if ( in_array( 'sr-only', $linkmod_classes, true ) ) {
$title = self::wrap_for_screen_reader( $title );
$keys_to_unset = array_keys( $linkmod_classes, 'sr-only' );
foreach ( $keys_to_unset as $k ) {
unset( $linkmod_classes[ $k ] );
}
}
// Put the item contents into $output.
$item_output .= isset( $args->link_before ) ? $args->link_before . $icon_html . $title . $args->link_after : '';
/**
* This is the end of the internal nav item. We need to close the
* correct element depending on the type of link or link mod.
*/
if ( '' !== $linkmod_type ) {
// is linkmod, output the required element opener.
$item_output .= self::linkmod_element_close( $linkmod_type, $attributes );
} else {
// With no link mod type set this must be a standard tag.
if ( evolve_theme_mod( 'evl_main_menu_hover_effect', 'rollover' ) == "disable" ) {
$item_output .= '';
} else {
$item_output .= '';
}
}
$item_output .= isset( $args->after ) ? $args->after : '';
/**
* END appending the internal item contents to the output.
*/
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
/**
* Traverse elements to create list from elements.
*
* Display one element if the element doesn't have any children otherwise,
* display the element and its children. Will only traverse up to the max
* depth and no ignore elements under that depth. It is possible to set the
* max depth to include all depths, see walk() method.
*
* This method should not be called directly, use the walk() method instead.
*
* @since WP 2.5.0
*
* @see Walker::start_lvl()
*
* @param object $element Data object.
* @param array $children_elements List of elements to continue traversing (passed by reference).
* @param int $max_depth Max depth to traverse.
* @param int $depth Depth of current element.
* @param array $args An array of arguments.
* @param string $output Used to append additional content (passed by reference).
*/
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
if ( ! $element ) {
return;
}
$id_field = $this->db_fields['id'];
// Display this element.
if ( is_object( $args[0] ) ) {
$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );
}
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
/**
* Menu Fallback
* =============
* If this function is assigned to the wp_nav_menu's fallback_cb variable
* and a menu has not been assigned to the theme location in the WordPress
* menu manager the function with display nothing to a non-logged in user,
* and will add a link to the WordPress menu manager if logged in as an admin.
*
* @param array $args passed from the wp_nav_menu function.
*/
public static function fallback( $args ) {
if ( current_user_can( 'edit_theme_options' ) ) {
/* Get Arguments. */
$container = $args['container'];
$container_id = $args['container_id'];
$container_class = $args['container_class'];
$menu_class = $args['menu_class'];
$menu_id = $args['menu_id'];
// initialize var to store fallback html.
$fallback_output = '';
if ( $container ) {
$fallback_output .= '<' . esc_attr( $container );
if ( $container_id ) {
$fallback_output .= ' id="' . esc_attr( $container_id ) . '"';
}
if ( $container_class ) {
$fallback_output .= ' class="' . esc_attr( $container_class ) . '"';
}
$fallback_output .= '>';
}
$fallback_output .= '
' . esc_html__( 'Add a menu', 'evolve' ) . '
';
$fallback_output .= '
';
if ( $container ) {
$fallback_output .= '' . esc_attr( $container ) . '>';
}
// if $args has 'echo' key and it's true echo, otherwise return.
if ( array_key_exists( 'echo', $args ) && $args['echo'] ) {
echo $fallback_output; // WPCS: XSS OK.
} else {
return $fallback_output;
}
}
}
/**
* Find any custom linkmod or icon classes and store in their holder
* arrays then remove them from the main classes array.
*
* Supported linkmods: .disabled, .dropdown-header, .dropdown-divider, .sr-only
* Supported iconsets: Font Awesome 4/5, Glypicons
*
* NOTE: This accepts the linkmod and icon arrays by reference.
*
* @since 4.0.0
*
* @param array $classes an array of classes currently assigned to the item.
* @param array $linkmod_classes an array to hold linkmod classes.
* @param array $icon_classes an array to hold icon classes.
* @param integer $depth an integer holding current depth level.
*
* @return array $classes a maybe modified array of classnames.
*/
private function seporate_linkmods_and_icons_from_classes( $classes, &$linkmod_classes, &$icon_classes, $depth ) {
// Loop through $classes array to find linkmod or icon classes.
foreach ( $classes as $key => $class ) {
// If any special classes are found, store the class in it's
// holder array and and unset the item from $classes.
if ( preg_match( '/^disabled|^sr-only/i', $class ) ) {
// Test for .disabled or .sr-only classes.
$linkmod_classes[] = $class;
unset( $classes[ $key ] );
} elseif ( preg_match( '/^dropdown-header|^dropdown-divider|^dropdown-item-text/i', $class ) && $depth > 0 ) {
// Test for .dropdown-header or .dropdown-divider and a
// depth greater than 0 - IE inside a dropdown.
$linkmod_classes[] = $class;
unset( $classes[ $key ] );
} elseif ( preg_match( '/^fa-(\S*)?|^fa(s|r|l|b)?(\s?)?$/i', $class ) ) {
// Font Awesome.
$icon_classes[] = $class;
unset( $classes[ $key ] );
} elseif ( preg_match( '/^glyphicon-(\S*)?|^glyphicon(\s?)$/i', $class ) ) {
// Glyphicons.
$icon_classes[] = $class;
unset( $classes[ $key ] );
}
}
return $classes;
}
/**
* Return a string containing a linkmod type and update $atts array
* accordingly depending on the decided.
*
* @since 4.0.0
*
* @param array $linkmod_classes array of any link modifier classes.
*
* @return string empty for default, a linkmod type string otherwise.
*/
private function get_linkmod_type( $linkmod_classes = array() ) {
$linkmod_type = '';
// Loop through array of linkmod classes to handle their $atts.
if ( ! empty( $linkmod_classes ) ) {
foreach ( $linkmod_classes as $link_class ) {
if ( ! empty( $link_class ) ) {
// check for special class types and set a flag for them.
if ( 'dropdown-header' === $link_class ) {
$linkmod_type = 'dropdown-header';
} elseif ( 'dropdown-divider' === $link_class ) {
$linkmod_type = 'dropdown-divider';
} elseif ( 'dropdown-item-text' === $link_class ) {
$linkmod_type = 'dropdown-item-text';
}
}
}
}
return $linkmod_type;
}
/**
* Update the attributes of a nav item depending on the limkmod classes.
*
* @since 4.0.0
*
* @param array $atts array of atts for the current link in nav item.
* @param array $linkmod_classes an array of classes that modify link or nav item behaviors or displays.
*
* @return array maybe updated array of attributes for item.
*/
private function update_atts_for_linkmod_type( $atts = array(), $linkmod_classes = array() ) {
if ( ! empty( $linkmod_classes ) ) {
foreach ( $linkmod_classes as $link_class ) {
if ( ! empty( $link_class ) ) {
// update $atts with a space and the extra classname...
// so long as it's not a sr-only class.
if ( 'sr-only' !== $link_class ) {
$atts['class'] .= ' ' . esc_attr( $link_class );
}
// check for special class types we need additional handling for.
if ( 'disabled' === $link_class ) {
// Convert link to '#' and unset open targets.
$atts['href'] = '#';
unset( $atts['target'] );
} elseif ( 'dropdown-header' === $link_class || 'dropdown-divider' === $link_class || 'dropdown-item-text' === $link_class ) {
// Store a type flag and unset href and target.
unset( $atts['href'] );
unset( $atts['target'] );
}
}
}
}
return $atts;
}
/**
* Wraps the passed text in a screen reader only class.
*
* @since 4.0.0
*
* @param string $text the string of text to be wrapped in a screen reader class.
*
* @return string the string wrapped in a span with the class.
*/
private function wrap_for_screen_reader( $text = '' ) {
if ( $text ) {
$text = '' . $text . '';
}
return $text;
}
/**
* Returns the correct opening element and attributes for a linkmod.
*
* @since 4.0.0
*
* @param string $linkmod_type a sting containing a linkmod type flag.
* @param string $attributes a string of attributes to add to the element.
*
* @return string a string with the openign tag for the element with attribibutes added.
*/
private function linkmod_element_open( $linkmod_type, $attributes = '' ) {
$output = '';
if ( 'dropdown-item-text' === $linkmod_type ) {
$output .= '';
} elseif ( 'dropdown-header' === $linkmod_type ) {
// For a header use a span with the .h6 class instead of a real
// header tag so that it doesn't confuse screen readers.
$output .= '