$args
* @param bool $echo
*/
function aksrt_icon_card(array $args = [], bool $echo = false): string {
$defaults = [
'type' => '',
'class' => 'box-body nopw-sm',
'icon' => '',
'icon_size' => 0,
'customize_icon' => '',
'icon_image' => '',
'link' => [
'url' => '',
'target' => '',
],
'icon_radius' => false,
'icon_color' => '',
'icon_custom_color' => '',
'icon_class' => '',
'title' => '',
'desc' => '',
];
$args = wp_parse_args($args, $defaults);
$icon_fa = sanitize_text_field((string) $args['icon']);
$icon_img = esc_url_raw(trim((string) ($args['icon_image'] !== '' ? $args['icon_image'] : $args['customize_icon'])));
// customize_icon may be raw HTML (img) from older data.
$custom_html = '';
if ($icon_img === '' && is_string($args['customize_icon']) && str_contains((string) $args['customize_icon'], '<')) {
$custom_html = wp_kses((string) $args['customize_icon'], [
'i' => ['class' => true, 'aria-hidden' => true],
'img' => ['src' => true, 'data-src' => true, 'alt' => true, 'class' => true, 'width' => true, 'height' => true],
'span'=> ['class' => true],
]);
}
if ($icon_fa === '' && $icon_img === '' && $custom_html === '') {
return '';
}
$link = $args['link'];
if (is_string($link)) {
$link = ['url' => $link, 'target' => ''];
}
if (!is_array($link)) {
$link = ['url' => '', 'target' => ''];
}
$url = esc_url(trim((string) ($link['url'] ?? '')));
$target = sanitize_text_field((string) ($link['target'] ?? ''));
$tgt = $target !== '' ? ' target="' . esc_attr($target) . '" rel="noopener noreferrer"' : '';
$icon_color = sanitize_html_class((string) $args['icon_color']);
$icon_class_extra = sanitize_html_class((string) $args['icon_class']);
$radius = !empty($args['icon_radius']);
$icon_class = $radius
? 'card-icon toggle-radius fa-3x ' . ($icon_class_extra !== '' ? $icon_class_extra : $icon_color)
: 'card-icon fa-4x ' . $icon_color;
if ($icon_class_extra !== '' && !$radius) {
$icon_class .= ' ' . $icon_class_extra;
}
$style = '';
$custom_color = sanitize_hex_color((string) $args['icon_custom_color']);
if (!$radius && $custom_color) {
$style = ' style="color:' . esc_attr($custom_color) . ';"';
}
if ($custom_html !== '') {
$icon_inner = $custom_html;
} elseif ($icon_img !== '') {
$icon_inner = '
';
} else {
if ($icon_fa !== '' && !str_contains($icon_fa, 'fa-') && !str_contains($icon_fa, ' ')) {
$icon_fa = 'fa fas fa-' . $icon_fa;
}
$icon_inner = '';
}
$icon = '' . $icon_inner . '';
if ($url !== '') {
$icon = '' . $icon . '';
}
$icon_size = (int) $args['icon_size'];
if ($icon_size > 0) {
$icon = '' . $icon . '';
}
$title = trim((string) $args['title']);
$desc = trim((string) $args['desc']);
if ($url !== '' && $title !== '') {
$title_html = '' . esc_html($title) . '';
} else {
$title_html = $title !== '' ? esc_html($title) : '';
}
$body = '';
if ($title_html !== '') {
$body .= '
' . $title_html . '
';
}
if ($desc !== '') {
$body .= '' . esc_html($desc) . '
';
}
$class = trim((string) $args['class'] . ' ' . (string) $args['type']);
$html = '';
$html .= $icon;
$html .= $body !== '' ? '
' . $body . '
' : '';
$html .= '
';
if ($echo) {
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return '';
}
return $html;
}
endif;
if (!function_exists('aksrt_icon_cover_card')) :
/**
* Horizontal icon cover card (icon left, title/desc right).
*
* @param array $args
* @param bool $echo
*/
function aksrt_icon_cover_card(array $args = [], bool $echo = false): string {
$defaults = [
'class' => 'zib-widget',
'icon' => '',
'icon_size' => 25,
'customize_icon' => '',
'custom_icon' => '',
'icon_image' => '',
'link' => [
'url' => '',
'target' => '',
],
// Flat keys used by header_components_icon_cards admin schema.
'url' => '',
'target' => '',
'icon_radius' => false,
'icon_color' => '',
'icon_custom_color' => '',
'icon_class' => '',
'title' => '',
'desc' => '',
];
$args = wp_parse_args($args, $defaults);
// Normalize link: accept nested link[] or flat url/target (SPA schema).
$link = $args['link'];
if (is_string($link)) {
$link = ['url' => $link, 'target' => (string) $args['target']];
}
if (!is_array($link)) {
$link = ['url' => '', 'target' => ''];
}
if (trim((string) ($link['url'] ?? '')) === '' && trim((string) $args['url']) !== '') {
$link['url'] = (string) $args['url'];
}
if (trim((string) ($link['target'] ?? '')) === '' && trim((string) $args['target']) !== '') {
$link['target'] = (string) $args['target'];
}
$icon_fa = trim((string) $args['icon']);
// custom_icon (SPA) + customize_icon (zibll) + icon_image URL.
$custom_src = (string) ($args['custom_icon'] !== '' ? $args['custom_icon'] : $args['customize_icon']);
$icon_img = esc_url_raw(trim((string) ($args['icon_image'] !== '' ? $args['icon_image'] : '')));
$custom_html = '';
if ($icon_img === '' && $custom_src !== '' && str_contains($custom_src, '<')) {
$custom_html = wp_kses($custom_src, [
'i' => ['class' => true, 'aria-hidden' => true],
'img' => ['src' => true, 'data-src' => true, 'alt' => true, 'class' => true, 'width' => true, 'height' => true],
'span' => ['class' => true],
'svg' => ['class' => true, 'viewbox' => true, 'viewBox' => true, 'width' => true, 'height' => true, 'fill' => true, 'xmlns' => true, 'aria-hidden' => true],
'path' => ['d' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true],
'use' => ['href' => true, 'xlink:href' => true],
]);
} elseif ($icon_img === '' && $custom_src !== '' && filter_var($custom_src, FILTER_VALIDATE_URL)) {
$icon_img = esc_url_raw($custom_src);
}
if ($icon_fa === '' && $icon_img === '' && $custom_html === '') {
return '';
}
$url = esc_url(trim((string) ($link['url'] ?? '')));
$target = sanitize_text_field((string) ($link['target'] ?? ''));
// zibll only adds target= when non-empty; keep same for 1:1.
$tgt = ($target !== '' && $target !== '_self') ? ' target="' . esc_attr($target) . '"' : '';
// zibll: class = "icon-cover-icon badg cir" + optional icon_class (may include radius4 / c-* / jb-*).
// Do NOT sanitize_html_class on the whole string — it collapses multi-token classes.
$icon_class_extra = trim(preg_replace('/\s+/', ' ', (string) $args['icon_class']));
$icon_class = 'icon-cover-icon badg cir';
if ($icon_class_extra !== '') {
$tokens = preg_split('/\s+/', $icon_class_extra) ?: [];
$safe = [];
foreach ($tokens as $tok) {
$tok = preg_replace('/[^a-zA-Z0-9_-]/', '', $tok);
if ($tok !== '') {
$safe[] = $tok;
}
}
if ($safe) {
$icon_class .= ' ' . implode(' ', $safe);
}
}
if (!empty($args['icon_radius']) && !str_contains($icon_class, 'radius4')) {
$icon_class .= ' radius4';
}
$icon_color = trim((string) $args['icon_color']);
if ($icon_color !== '' && !str_contains($icon_class, $icon_color)) {
$icon_class .= ' ' . preg_replace('/[^a-zA-Z0-9_-]/', '', $icon_color);
}
$icon_size = max(14, min(64, (int) $args['icon_size']));
// zibll always sets font-size on the icon badge.
$style = 'font-size: ' . $icon_size . 'px;';
$custom_color = sanitize_hex_color((string) $args['icon_custom_color']);
if ($custom_color) {
$style .= 'color:' . $custom_color . ';';
}
if ($custom_html !== '') {
$icon_inner = $custom_html;
} elseif ($icon_img !== '') {
$icon_inner = '
';
} else {
// zibll: zib_get_cfs_icon($args['icon'], 'em09') — keep FA class + em09.
if ($icon_fa !== '' && !str_contains($icon_fa, 'fa-') && !str_contains($icon_fa, ' ') && !str_starts_with($icon_fa, 'zibsvg-')) {
$icon_fa = 'fa fas fa-' . $icon_fa;
}
if (str_contains($icon_fa, '<')) {
$icon_inner = wp_kses($icon_fa, [
'i' => ['class' => true, 'aria-hidden' => true],
'svg' => ['class' => true, 'viewbox' => true, 'viewBox' => true, 'width' => true, 'height' => true, 'fill' => true, 'xmlns' => true, 'aria-hidden' => true],
'path' => ['d' => true, 'fill' => true],
'use' => ['href' => true, 'xlink:href' => true],
]);
} else {
$icon_inner = '';
}
}
$icon = '' . $icon_inner . '
';
// zibll allows HTML in title/desc (admin stores badges etc.).
$title = (string) $args['title'];
$desc = (string) $args['desc'];
$allow = [
'badge' => ['class' => true],
'span' => ['class' => true],
'i' => ['class' => true, 'aria-hidden' => true],
'em' => ['class' => true],
'strong' => ['class' => true],
'b' => [],
'small' => ['class' => true],
'br' => [],
];
$text = '';
if (trim(wp_strip_all_tags($title)) !== '' || str_contains($title, '<')) {
$text .= ' ' . wp_kses($title, $allow) . '
';
}
if (trim(wp_strip_all_tags($desc)) !== '' || str_contains($desc, '<')) {
$text .= ' ' . wp_kses($desc, $allow) . '
';
}
$html = '';
if ($url !== '') {
// zibll:
$html .= '';
}
$html .= '';
$html .= $icon;
$html .= $text !== '' ? '
' . $text . '
' : '';
$html .= '
';
if ($url !== '') {
$html .= '';
}
if ($echo) {
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return '';
}
return $html;
}
endif;
if (!function_exists('aksrt_obs_animate_attrs')) :
/**
* Build class + attribute string for scroll-in animation (maps to data-aksrt-animate).
*
* @param string $animation fade|slideup|slidedown|slideright|slideleft|zoomin|zoomout|''
* @param bool $repeat
* @param float|int $delay_s
* @return array{class:string,attr:string}
*/
function aksrt_obs_animate_attrs(string $animation, bool $repeat = false, $delay_s = 0): array {
$animation = sanitize_key($animation);
$map = [
'fade' => 'fadeIn',
'slideup' => 'fadeInUp',
'slidedown' => 'fadeInDown',
'slideright' => 'fadeInRight',
'slideleft' => 'fadeInLeft',
'zoomin' => 'zoomIn',
'zoomout' => 'fadeIn',
'fadein' => 'fadeIn',
'fadeinup' => 'fadeInUp',
];
if ($animation === '' || !isset($map[$animation]) && !in_array($animation, $map, true)) {
if (!isset($map[$animation])) {
return ['class' => '', 'attr' => ''];
}
}
$aksrt = $map[$animation] ?? $animation;
$delay_ms = (int) round(((float) $delay_s) * 1000);
$class = ' obs-animate ani-' . $animation;
$attr = ' data-aksrt-animate="' . esc_attr($aksrt) . '"';
if ($delay_ms > 0) {
$attr .= ' data-aksrt-animate-delay="' . esc_attr((string) $delay_ms) . '"';
}
if ($repeat) {
$attr .= ' data-animation-repeat="true"';
}
return ['class' => $class, 'attr' => $attr];
}
endif;