diff --git a/assets/widgets/admin.css b/assets/widgets/admin.css index a5a68d8a..a83dac51 100644 --- a/assets/widgets/admin.css +++ b/assets/widgets/admin.css @@ -98,6 +98,16 @@ align-items: center; } +.aksrt-widget-remote-picker { position: relative; } +.aksrt-widget-remote-picker > select { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); } +.aksrt-widget-remote-picker__selected { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 6px; } +.aksrt-widget-remote-picker__tag { padding: 4px 8px; border: 1px solid #c3c4c7; border-radius: 3px; background: #f6f7f7; color: #2c3338; cursor: pointer; } +.aksrt-widget-remote-picker__tag::after { margin-left: 6px; color: #787c82; content: "×"; } +.aksrt-widget-remote-picker__results { position: absolute; z-index: 20; right: 0; left: 0; max-height: 210px; overflow-y: auto; border: 1px solid #8c8f94; border-top: 0; background: #fff; box-shadow: 0 4px 8px rgba(0, 0, 0, .12); } +.aksrt-widget-remote-picker__result, .aksrt-widget-remote-picker__status { display: block; width: 100%; padding: 7px 9px; border: 0; background: #fff; color: #2c3338; text-align: left; } +.aksrt-widget-remote-picker__result { cursor: pointer; } +.aksrt-widget-remote-picker__result:hover, .aksrt-widget-remote-picker__result:focus { background: #f0f6fc; color: #135e96; } + .aksrt-widget-upload { display: flex; flex-wrap: wrap; diff --git a/assets/widgets/admin.js b/assets/widgets/admin.js index b97437c9..4eb9f538 100644 --- a/assets/widgets/admin.js +++ b/assets/widgets/admin.js @@ -16,11 +16,73 @@ const output = this.parentElement.querySelector('output'); if (output) this.addEventListener('input', () => { output.textContent = this.value; }); }); + initRemoteSelects($root); evaluateDependencies($root); updateWidgetTitle($root); updatePlacementWarning($root); } + function initRemoteSelects(root) { + $(root).find('select.aksrt-widget-remote-select').each(function () { + const $select = $(this); + if ($select.data('remote-ready')) return; + $select.data('remote-ready', true); + const $picker = $('
'); + const $selected = $(''); + const $search = $('').attr('placeholder', String($select.data('placeholder') || '输入关键词以搜索')); + const $results = $(''); + $select.wrap($picker); + $select.after($selected, $search, $results); + + const renderSelected = () => { + $selected.empty(); + $select.find('option:selected').each(function () { + const $tag = $('').text($(this).text()).attr('aria-label', `移除 ${$(this).text()}`); + $tag.on('click', () => { $(this).remove(); $select.trigger('change'); renderSelected(); }); + $selected.append($tag); + }); + }; + + let timer = 0; + $search.on('input', function () { + window.clearTimeout(timer); + const query = String(this.value || '').trim(); + const minLength = Number($select.data('min-length') || 0); + if (query.length < minLength) { $results.prop('hidden', true).empty(); return; } + timer = window.setTimeout(() => { + $results.prop('hidden', false).empty().append($('').text(config.i18n?.loading || '正在加载…')); + $.post(config.ajaxUrl, { + action: config.searchAction, + nonce: config.nonce, + source: $select.data('option-source'), + queryArgs: $select.attr('data-query-args') || '{}', + search: query, + }).done((response) => { + $results.empty(); + const items = response?.success && Array.isArray(response.data?.results) ? response.data.results : []; + if (!items.length) { $results.append($('').text('未找到匹配内容')); return; } + items.forEach((item) => { + const id = String(item.id || ''); + const text = String(item.text || `#${id}`); + const $button = $('').text(text); + $button.on('click', () => { + let $option = $select.find('option').filter(function () { return String(this.value) === id; }).first(); + if (!$option.length) $option = $('').val(id).text(text).appendTo($select); + $option.prop('selected', true); + $select.trigger('change'); + renderSelected(); + $search.val('').trigger('focus'); + $results.prop('hidden', true).empty(); + }); + $results.append($button); + }); + }).fail(() => $results.empty().append($('').text(config.i18n?.error || '加载失败,请重试。'))); + }, 250); + }); + renderSelected(); + }); + } + function updateWidgetTitle(root) { const $root = $(root); const title = String($root.find('.aksrt-widget-field[data-field-id="title"] input').first().val() || '').trim(); diff --git a/assets/widgets/frontend.css b/assets/widgets/frontend.css index 5df1d1cc..fbaf5b20 100644 --- a/assets/widgets/frontend.css +++ b/assets/widgets/frontend.css @@ -99,15 +99,27 @@ .aksrt-widget-text-title { padding: 18px 0; }.aksrt-widget-text-title.is-center { text-align: center; }.aksrt-widget-text-title.is-right { text-align: right; } .aksrt-widget-text-title h2 { margin: 0; font-size: clamp(26px,4vw,44px); line-height: 1.25; }.aksrt-widget-text-title p { margin: 12px 0 0; color: var(--muted-color,#8a8c98); line-height: 1.8; } -.aksrt-widget-buttons { display: flex; flex-wrap: wrap; gap: var(--aksrt-button-gap,10px); }.aksrt-widget-buttons.is-center { justify-content: center; }.aksrt-widget-buttons.is-right { justify-content: flex-end; } -.aksrt-widget-button { display: inline-flex; min-height: 40px; padding: 9px 18px; align-items: center; justify-content: center; gap: 7px; border: 0; border-radius: 9px; background: var(--focus-color,#ff5473); color: #fff !important; font-weight: 600; cursor: pointer; transition: filter .2s, transform .2s; } -.aksrt-widget-button:hover { filter: brightness(1.07); transform: translateY(-1px); }.aksrt-widget-button.is-secondary { background: rgba(127,127,127,.12); color: inherit !important; } +.aksrt-user-card__guest-actions .aksrt-widget-button, .aksrt-user-card__actions > .aksrt-widget-button { display: inline-flex; min-height: 40px; padding: 9px 18px; align-items: center; justify-content: center; gap: 7px; border: 0; border-radius: 9px; background: var(--focus-color,#ff5473); color: #fff !important; font-weight: 600; cursor: pointer; transition: filter .2s, transform .2s; } +.aksrt-user-card__guest-actions .aksrt-widget-button:hover, .aksrt-user-card__actions > .aksrt-widget-button:hover { filter: brightness(1.07); transform: translateY(-1px); }.aksrt-user-card__guest-actions .aksrt-widget-button.is-secondary { background: rgba(127,127,127,.12); color: inherit !important; } .aksrt-widget-gap { height: var(--aksrt-gap); } .aksrt-widget-tag-cloud { display: flex; flex-wrap: wrap; gap: 8px; }.aksrt-widget-tag-cloud a { padding: 6px 11px; border-radius: 6px; background: rgba(127,127,127,.1); font-size: 13px; transition: background .2s,color .2s; }.aksrt-widget-tag-cloud a:hover { background: var(--focus-color,#ff5473); color: #fff; }.aksrt-widget-tag-cloud small { margin-left: 5px; opacity: .65; } .aksrt-widget-comments { display: grid; gap: 15px; margin: 0; padding: 0; list-style: none; }.aksrt-widget-comments li { display: flex; gap: 11px; }.aksrt-widget-comments__avatar img { width: 42px; height: 42px; border-radius: 50%; }.aksrt-widget-comments p { margin: 3px 0; color: var(--muted-color,#8a8c98); font-size: 13px; line-height: 1.55; }.aksrt-widget-comments__source { font-size: 12px; opacity: .65; } .aksrt-widget-links { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 10px; }.aksrt-widget-links a { display: flex; flex-direction: column; gap: 4px; padding: 10px 8px; border-radius: var(--main-radius,8px); background: var(--muted-border-color,#f2f3f5); color:var(--key-color,#333); }.aksrt-widget-links small { color: var(--muted-color,#8a8c98); }.aksrt-widget-links--simple { display: flex; flex-wrap: wrap; }.aksrt-widget-links--simple a { padding: 5px 9px; box-shadow: none; background: transparent; } -.aksrt-widget-notice { display: flex; height: 48px; align-items: center; gap: 12px; padding: 0 15px; overflow: hidden; border-radius: var(--main-radius,8px); background: var(--main-bg-color,#fff); box-shadow: 0 0 10px var(--main-shadow,rgba(116,116,116,.08)); }.aksrt-widget-notice .swiper { height: 48px; flex: 1; }.aksrt-widget-notice .swiper-slide, .aksrt-widget-notice .swiper-slide a { display: flex; height: 48px; align-items: center; gap: 10px; }.aksrt-widget-notice .swiper-slide span { overflow: hidden; color: var(--muted-color,#8a8c98); text-overflow: ellipsis; white-space: nowrap; } -.aksrt-widget-swiper { position: relative; } +.widget-buttons-wrap { margin: calc(0px - var(--pc-gap, 10px)); } +.widget-buttons-wrap > div { margin: var(--pc-gap, 10px); } +.widget-buttons-wrap .but { width: var(--pc-width, auto); } +.widget-buttons-wrap.align-center { justify-content: center; } +.widget-buttons-wrap.align-right { justify-content: flex-end; } +.widget-buttons-wrap.align-left { justify-content: flex-start; } +.widget-buttons.pc-size-small .but { padding: .3em .6em; } +.widget-buttons.pc-size-medium .but { padding: 8px 16px; } +.widget-buttons.pc-size-large .but { padding: 12px 24px; } +.swiper-bulletin { padding: .1em 6px; background: var(--this-bg); } +.swiper-bulletin .new-swiper { line-height: 2.4em; height: 2.4em; overflow: hidden; } +.swiper-bulletin a { color: var(--this-color); } +.bulletin-icon { background: var(--this-color); width: 26px; height: 26px; text-align: center; border-radius: 30px; color: #fff; font-size: 18px; } +.swiper-bulletin[class*="b-"] .bulletin-icon { color: var(--this-bg); } +.swiper-bulletin[class*="jb-"] .bulletin-icon { color: var(--this-bg-b); } .aksrt-term-card { display: block; overflow: hidden; border-radius: var(--aksrt-widget-radius); background: var(--main-bg-color,#fff); box-shadow: 0 0 10px var(--main-shadow,rgba(116,116,116,.08)); }.aksrt-term-card__media { display: block; aspect-ratio: 16/9; background: var(--muted-border-color,#eee); }.aksrt-term-card__media img { width: 100%; height: 100%; object-fit: cover; }.aksrt-term-card__body { display: flex; flex-direction: column; gap: 5px; padding: 14px; }.aksrt-term-card__body small { min-height: 38px; color: var(--muted-color,#8a8c98); }.aksrt-term-card__body em { font-size: 12px; color: var(--focus-color,#ff5473); font-style: normal; } .aksrt-term-aggregation { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 15px; }.aksrt-term-aggregation__card { padding: 15px; border-radius: var(--aksrt-widget-radius); background: var(--main-bg-color,#fff); box-shadow: 0 0 10px var(--main-shadow,rgba(116,116,116,.08)); }.aksrt-term-aggregation header a { display: flex; justify-content: space-between; }.aksrt-term-aggregation header span { color: var(--muted-color,#8a8c98); font-size: 13px; }.aksrt-term-aggregation ul { display: grid; gap: 10px; margin: 14px 0 0; padding: 0; list-style: none; }.aksrt-term-aggregation li a { display: flex; align-items: center; gap: 10px; }.aksrt-term-aggregation li img { width: 55px; height: 42px; border-radius: 6px; object-fit: cover; } @@ -133,6 +145,12 @@ .aksrt-widget-grid { grid-template-columns: repeat(var(--aksrt-cols-m,1),minmax(0,1fr)); gap: 10px; } .aksrt-widget__header { align-items: flex-start; flex-direction: column; }.aksrt-widget__title-links { justify-content: flex-start; } .aksrt-widget-links { grid-template-columns: repeat(2,minmax(0,1fr)); } + .widget-buttons-wrap { margin: calc(0px - var(--m-gap, 5px)); } + .widget-buttons-wrap > div { margin: var(--m-gap, 5px); } + .widget-buttons-wrap .but { width: var(--m-width, auto); } + .widget-buttons.m-size-small .but { padding: .3em .6em; } + .widget-buttons.m-size-medium .but { padding: 8px 16px; } + .widget-buttons.m-size-large .but { padding: 12px 24px; } .aksrt-widget-partners__track { grid-template-rows: repeat(var(--aksrt-partner-rows-m),70px); } .aksrt-term-aggregation, .aksrt-feature-intro__panels article, .aksrt-slider-combo { grid-template-columns: 1fr; } .aksrt-highlight--large { grid-column: auto; } diff --git a/src/WidgetSystem/AdminFormController.php b/src/WidgetSystem/AdminFormController.php index 019e966f..e36d2a88 100644 --- a/src/WidgetSystem/AdminFormController.php +++ b/src/WidgetSystem/AdminFormController.php @@ -9,10 +9,12 @@ defined('ABSPATH') || exit; */ final class AdminFormController { public const AJAX_ACTION = 'aksrt_widget_form'; + public const SEARCH_ACTION = 'aksrt_widget_remote_options'; private const NONCE_ACTION = 'aksrt_widget_form'; public static function register_hooks(): void { add_action('wp_ajax_' . self::AJAX_ACTION, [self::class, 'ajax_form']); + add_action('wp_ajax_' . self::SEARCH_ACTION, [self::class, 'ajax_remote_options']); add_action('admin_enqueue_scripts', [self::class, 'enqueue']); add_action('customize_controls_enqueue_scripts', [self::class, 'enqueue']); } @@ -33,6 +35,7 @@ final class AdminFormController { wp_localize_script('aksrt-widget-admin', 'aksrtWidgetAdmin', [ 'ajaxUrl' => admin_url('admin-ajax.php'), 'action' => self::AJAX_ACTION, + 'searchAction' => self::SEARCH_ACTION, 'nonce' => wp_create_nonce(self::NONCE_ACTION), 'transferNonce' => wp_create_nonce('aksrt_widgets_transfer'), 'i18n' => [ @@ -64,5 +67,39 @@ final class AdminFormController { $html = (string) ob_get_clean(); wp_send_json_success(['html' => $html]); } + + public static function ajax_remote_options(): void { + check_ajax_referer(self::NONCE_ACTION, 'nonce'); + if (!current_user_can('edit_theme_options')) { + wp_send_json_error(['message' => __('权限不足。', 'aksrt')], 403); + } + + $source = isset($_POST['source']) ? sanitize_key(wp_unslash($_POST['source'])) : ''; + $search = isset($_POST['search']) ? sanitize_text_field(wp_unslash($_POST['search'])) : ''; + $query_json = isset($_POST['queryArgs']) ? wp_unslash($_POST['queryArgs']) : ''; + $query_args = is_string($query_json) ? json_decode($query_json, true) : []; + $query_args = is_array($query_args) ? $query_args : []; + $results = []; + + if ($source === 'post' && sanitize_key((string) ($query_args['post_type'] ?? '')) === 'plate') { + $posts = get_posts([ + 'post_type' => 'plate', + 'post_status' => 'publish', + 'posts_per_page' => 20, + 's' => $search, + 'orderby' => 'relevance date', + 'order' => 'DESC', + ]); + foreach ($posts as $post) $results[] = ['id' => (string) $post->ID, 'text' => get_the_title($post) ?: '#' . $post->ID]; + } elseif ($source === 'categories') { + $taxonomy = sanitize_key((string) ($query_args['taxonomy'] ?? '')); + if (in_array($taxonomy, ['forum_topic', 'forum_tag'], true) && taxonomy_exists($taxonomy)) { + $terms = get_terms(['taxonomy' => $taxonomy, 'hide_empty' => false, 'number' => 20, 'search' => $search]); + if (!is_wp_error($terms)) foreach ($terms as $term) $results[] = ['id' => (string) $term->term_id, 'text' => (string) $term->name]; + } + } + + wp_send_json_success(['results' => $results]); + } } diff --git a/src/WidgetSystem/CommonFields.php b/src/WidgetSystem/CommonFields.php index a5acc533..5df1dba5 100644 --- a/src/WidgetSystem/CommonFields.php +++ b/src/WidgetSystem/CommonFields.php @@ -81,10 +81,13 @@ final class CommonFields { public static function palette(): array { return [ - 'focus-color' => '主题色', 'jb-blue' => '渐变蓝', 'jb-cyan' => '渐变青', - 'jb-green' => '渐变绿', 'jb-yellow' => '渐变黄', 'jb-red' => '渐变红', - 'jb-pink' => '渐变粉', 'jb-purple' => '渐变紫', 'c-blue' => '蓝色', - 'c-green' => '绿色', 'c-yellow' => '黄色', 'c-red' => '红色', + 'focus-color' => '主题色', 'key-color' => '主要文字', 'muted-color' => '次要文字', + 'c-red' => '红色', 'c-red-2' => '深红', 'c-yellow' => '黄色', 'c-yellow-2' => '深黄', + 'c-cyan' => '青色', 'c-blue' => '蓝色', 'c-blue-2' => '深蓝', 'c-green' => '绿色', 'c-green-2' => '深绿', + 'c-purple' => '紫色', 'c-purple-2' => '深紫', 'b-red' => '红色背景', 'b-yellow' => '黄色背景', + 'b-cyan' => '青色背景', 'b-blue' => '蓝色背景', 'b-green' => '绿色背景', 'b-purple' => '紫色背景', 'b-black' => '黑色背景', + 'jb-blue' => '渐变蓝', 'jb-cyan' => '渐变青', 'jb-green' => '渐变绿', 'jb-yellow' => '渐变黄', + 'jb-red' => '渐变红', 'jb-pink' => '渐变粉', 'jb-purple' => '渐变紫', 'jb-vip1' => '会员金', 'jb-vip2' => '会员黑', ]; } } diff --git a/src/WidgetSystem/FieldSchema.php b/src/WidgetSystem/FieldSchema.php index 15992fa5..810f7e5c 100644 --- a/src/WidgetSystem/FieldSchema.php +++ b/src/WidgetSystem/FieldSchema.php @@ -84,6 +84,9 @@ final class FieldSchema { return !empty($field['allow_html']) ? wp_kses_post((string) $value) : sanitize_textarea_field((string) $value); case 'text': default: + if (($field['sanitize'] ?? '') === 'url') { + return esc_url_raw((string) $value); + } if (($field['sanitize'] ?? '') === 'ids') { return implode(',', array_values(array_unique(array_filter(array_map('absint', preg_split('/[,,\s]+/', (string) $value)))))); } @@ -122,7 +125,21 @@ final class FieldSchema { } private static function choice(array $field, $value) { - $options = (array) ($field['options'] ?? []); + $raw_options = $field['options'] ?? []; + // Reference-theme AJAX selects declare an option source (for example + // `post` or `categories`) instead of an inline option map. Preserve the + // selected IDs until the remote picker resolves their labels. + if (!is_array($raw_options)) { + if (!empty($field['multiple'])) { + $values = is_array($value) ? $value : preg_split('/[,,\s]+/', (string) $value, -1, PREG_SPLIT_NO_EMPTY); + return array_values(array_unique(array_filter(array_map(static function ($item): string { + $item = trim((string) $item); + return preg_match('/^\d+$/', $item) ? (string) (int) $item : ''; + }, $values ?: [])))); + } + return sanitize_text_field((string) $value); + } + $options = $raw_options; if (!empty($field['multiple'])) { $values = is_array($value) ? $value : []; return array_values(array_filter(array_map('strval', $values), static fn($item) => array_key_exists($item, $options))); diff --git a/src/WidgetSystem/FormRenderer.php b/src/WidgetSystem/FormRenderer.php index c7ebd254..fdd0c90f 100644 --- a/src/WidgetSystem/FormRenderer.php +++ b/src/WidgetSystem/FormRenderer.php @@ -128,6 +128,10 @@ final class FormRenderer { private static function select(string $id, string $name, array $field, $value): void { $multiple = !empty($field['multiple']); + if (!is_array($field['options'] ?? [])) { + self::remote_select($id, $name, $field, $value); + return; + } echo ''; } + private static function remote_select(string $id, string $name, array $field, $value): void { + $values = array_values(array_unique(array_filter(array_map('absint', (array) $value)))); + $options = self::remote_selected_options($field, $values); + $source = (string) ($field['options'] ?? ''); + $query_args = wp_json_encode((array) ($field['query_args'] ?? [])); + $min_length = max(0, (int) ($field['settings']['min_length'] ?? 0)); + $placeholder = (string) ($field['placeholder'] ?? __('输入关键词以搜索', 'aksrt')); + echo ''; + } + + private static function remote_selected_options(array $field, array $values): array { + $options = []; + $source = (string) ($field['options'] ?? ''); + $query_args = (array) ($field['query_args'] ?? []); + foreach ($values as $value) { + $label = ''; + if ($source === 'post' && function_exists('get_the_title')) { + $label = (string) get_the_title($value); + } elseif ($source === 'categories' && function_exists('get_term')) { + $term = get_term($value, sanitize_key((string) ($query_args['taxonomy'] ?? ''))); + if ($term && !is_wp_error($term)) $label = (string) $term->name; + } + $options[$value] = $label !== '' ? $label : '#' . $value; + } + return $options; + } + private static function checkboxes(string $id, string $name, array $field, $value): void { $options = (array) ($field['options'] ?? []); if (!$options) { diff --git a/src/WidgetSystem/FrontendRenderer.php b/src/WidgetSystem/FrontendRenderer.php index b4bdad08..00370fed 100644 --- a/src/WidgetSystem/FrontendRenderer.php +++ b/src/WidgetSystem/FrontendRenderer.php @@ -23,7 +23,7 @@ final class FrontendRenderer { } AssetManager::enqueue_for($definition); - if (in_array($definition->slug(), ['tab_posts', 'slider', 'slider_media_combo', 'icon_cards', 'icon_cover_cards'], true)) { + if (in_array($definition->slug(), ['tab_posts', 'slider', 'slider_media_combo', 'icon_cards', 'icon_cover_cards', 'buttons', 'notice'], true)) { echo (string) ($args['before_widget'] ?? ''); echo self::reference_title($instance); echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped diff --git a/src/WidgetSystem/Renderers/GeneralRenderer.php b/src/WidgetSystem/Renderers/GeneralRenderer.php index b4591abd..a20a0569 100644 --- a/src/WidgetSystem/Renderers/GeneralRenderer.php +++ b/src/WidgetSystem/Renderers/GeneralRenderer.php @@ -3,6 +3,7 @@ namespace AKSRT\WidgetSystem\Renderers; use AKSRT\WidgetSystem\RendererHelpers; +use AKSRT\WidgetSystem\PostQuery; defined('ABSPATH') || exit; @@ -156,15 +157,35 @@ final class GeneralRenderer { } private static function render_buttons(array $i): string { - $html = ''; + $button_class = 'but' . (!empty($i['radius']) ? ' radius' : '') . (!empty($i['hollow']) ? ' hollow' : ''); + $buttons = ''; + foreach ((array) ($i['items'] ?? []) as $index => $item) { + if (!is_array($item) || trim((string) ($item['text'] ?? '')) === '') continue; + $link = RendererHelpers::link((array) ($item['link'] ?? [])); + $url = $link['url'] !== '' ? $link['url'] : 'javascript:void(0)'; + if (!empty($i['go_link']) && $link['url'] !== '' && function_exists('aksrt_go_link')) $url = esc_url(aksrt_go_link($link['url'], true)); + $target = $link['target'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : ''; + $color = sanitize_html_class((string) ($item['color'] ?? '')); + $item_class = trim($button_class . ' ' . $color); + $icon_left = !empty($item['icon_left']) ? self::icon_markup((string) $item['icon_left']) : ''; + $icon_right = !empty($item['icon_right']) ? '' . self::icon_markup((string) $item['icon_right']) . '' : ''; + $animation = ''; + $attr = ''; + if (!empty($i['obs_animation'])) { + $animation = ' obs-animate ani-' . sanitize_html_class((string) $i['obs_animation']); + $attr = ' data-animation="' . esc_attr((string) $i['obs_animation']) . '" style="--delay:' . (float) $index * 0.15 . 's;"' . (!empty($i['animation_repeat']) ? ' data-animation-repeat="true"' : ''); + } + $buttons .= ''; + } + if ($buttons === '') return ''; + return ''; } private static function render_layout_gap(array $i): string { @@ -218,12 +239,82 @@ final class GeneralRenderer { } private static function render_notice(array $i): string { - $slides = ''; - foreach ((array) $i['items'] as $item) { - $link = RendererHelpers::link((array) ($item['link'] ?? [])); - $content = '' . esc_html((string) ($item['title'] ?? '')) . '' . esc_html((string) ($item['description'] ?? '')) . ''; - $slides .= ''; + $source = (string) ($i['source'] ?? ''); + $lists = (array) ($i['img_ids'] ?? []); + $posts_query = false; + if ($source === 'posts' && class_exists(PostQuery::class)) { + $query_args = array_merge((array) ($i['posts_opts'] ?? []), ['count' => (int) ($i['count'] ?? 8), 'paginate' => '']); + $posts_query = PostQuery::build($query_args, 1); + $lists = []; + if ($posts_query && method_exists($posts_query, 'have_posts')) { + while ($posts_query->have_posts()) { + $posts_query->the_post(); + $subtitle = class_exists('AKSRT\\Core\\PostMetaBox') ? \AKSRT\Core\PostMetaBox::get_meta_value(get_the_ID(), 'subtitle', '') : ''; + $title = trim(wp_strip_all_tags(get_the_title())) . trim(wp_strip_all_tags((string) $subtitle)); + if (!empty($i['desc_s'])) { + $description = class_exists('AKSRT\\Core\\PostMetaBox') ? \AKSRT\Core\PostMetaBox::get_meta_value(get_the_ID(), 'description', '') : ''; + if (trim((string) $description) === '') $description = get_the_excerpt(); + $title .= ': ' . wp_html_excerpt(wp_strip_all_tags((string) $description), 160, '...'); + } + $lists[] = ['title' => $title, 'href' => get_permalink()]; + } + wp_reset_postdata(); + } + } elseif ($source === 'forums' && function_exists('zib_bbs_get_posts_query') && (!function_exists('_pz') || _pz('bbs_s'))) { + $query_args = (array) ($i['forums_opts'] ?? []); + $query_args['plate'] = $query_args['plate'] ?? 0; + $query_args['paged_size'] = (int) ($i['count'] ?? 8); + $query_args['paged'] = 1; + $query_args['no_found_rows'] = true; + $posts_query = zib_bbs_get_posts_query($query_args); + $lists = []; + if ($posts_query && method_exists($posts_query, 'have_posts')) { + while ($posts_query->have_posts()) { + $posts_query->the_post(); + $post_id = get_the_ID(); + $subtitle = class_exists('AKSRT\\Core\\PostMetaBox') ? \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'subtitle', '') : ''; + $title = trim(wp_strip_all_tags(get_the_title())) . trim(wp_strip_all_tags((string) $subtitle)); + if (!empty($i['desc_s'])) { + $description = class_exists('AKSRT\\Core\\PostMetaBox') ? \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'description', '') : ''; + if (trim((string) $description) === '') $description = get_the_excerpt(); + $title .= ': ' . wp_html_excerpt(wp_strip_all_tags((string) $description), 160, '...'); + } + $lists[] = ['title' => $title, 'href' => get_permalink()]; + } + wp_reset_postdata(); + } } - return ''; + $msg_icon = ($posts_query && !empty($i['msg_icon'])) ? self::notice_icon((string) $i['msg_icon']) : ''; + $slides = ''; + $blank = !empty($i['blank']) ? ' target="_blank" rel="noopener noreferrer"' : ''; + foreach ($lists as $notice) { + if (!is_array($notice) || trim((string) ($notice['title'] ?? '')) === '') continue; + $href = !empty($notice['href']) ? esc_url((string) $notice['href']) : 'javascript:void(0);'; + $icon = !empty($notice['icon']) ? self::notice_icon((string) $notice['icon']) : ''; + $title = wp_kses_post((string) ($notice['title'] ?? '')); + $slides .= ''; + } + $class = 'swiper-bulletin mb20 ' . sanitize_html_class((string) ($i['color'] ?? 'c-blue')) . (!empty($i['radius']) ? ' radius' : ' main-radius') . ($posts_query ? ' has-posts flex ac' : ''); + $html = '