esc_html__('横向无缝滚动的合作伙伴/友情链接条。', 'aksrt'), 'classname' => 'widget_aksrt_partners_scroll', ] ); } public function widget($args, $instance): void { $partners = $this->resolve_partners($instance); if (!$partners) { if (current_user_can('manage_options')) { echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无合作伙伴,请在模块中添加', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped : '

' . esc_html__('暂无合作伙伴', 'aksrt') . '

'; echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } return; } $rows = max(1, min(4, (int) ($instance['rows'] ?? 1))); $m_rows = max(1, min(4, (int) ($instance['m_rows'] ?? 1))); $style_type = sanitize_key((string) ($instance['style_type'] ?? 'card')); if (!in_array($style_type, ['card', 'logo', 'chip'], true)) { $style_type = 'card'; } $card_w = max(60, min(400, (int) ($instance['card_width'] ?? 220))); $card_h = max(40, min(200, (int) ($instance['card_height'] ?? 90))); $speed = max(1, min(20, (int) ($instance['speed'] ?? 3))); $direction = sanitize_key((string) ($instance['direction'] ?? 'alternate')); $pause = !empty($instance['pause_hover']) || !isset($instance['pause_hover']); $card_bg = !empty($instance['card_bg']) || !isset($instance['card_bg']); $end_fade = !empty($instance['end_fade']) || !isset($instance['end_fade']); $go_link = !empty($instance['go_link']); $show_bg = !empty($instance['show_widget_bg']) || !isset($instance['show_widget_bg']); $radius = max(0, min(40, (int) ($instance['card_radius'] ?? 10))); $use_rows = wp_is_mobile() ? $m_rows : $rows; $rows_data = array_fill(0, $use_rows, []); foreach (array_values($partners) as $i => $p) { $rows_data[$i % $use_rows][] = $p; } $rows_data = array_values(array_filter($rows_data, static fn($r) => !empty($r))); echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base); if ($title !== '') { echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } $wrap_class = 'aksrt-partners-scroll aksrt-ps-style-' . $style_type; if ($pause) { $wrap_class .= ' aksrt-ps-pause-hover'; } if ($card_bg) { $wrap_class .= ' aksrt-ps-card-bg'; } if ($end_fade) { $wrap_class .= ' aksrt-ps-end-fade'; } $style = sprintf( '--aksrt-ps-w:%dpx;--aksrt-ps-h:%dpx;--aksrt-ps-radius:%dpx;--aksrt-ps-speed:%d;', $card_w, $card_h, $radius, $speed ); $outer = $show_bg ? 'aksrt-partners-scroll-wrap' : 'aksrt-partners-scroll-wrap is-bare'; echo '
'; echo '
'; foreach ($rows_data as $row_index => $row_partners) { switch ($direction) { case 'left': $dir = 'left'; break; case 'right': $dir = 'right'; break; default: $dir = ($row_index % 2 === 0) ? 'left' : 'right'; } echo '
'; echo '
'; // Duplicate group for seamless CSS marquee. for ($dup = 0; $dup < 2; $dup++) { echo '
'; foreach ($row_partners as $partner) { echo $this->render_card($partner, $style_type, $go_link); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } echo '
'; } echo '
'; } echo '
'; echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * @param array $partner */ private function render_card(array $partner, string $style_type, bool $go_link): string { $title = trim((string) ($partner['title'] ?? '')); $desc = trim((string) ($partner['desc'] ?? '')); $image = (string) ($partner['image'] ?? ''); $url = (string) ($partner['url'] ?? ''); $target = (string) ($partner['target'] ?? ''); if ($image === '' && $title === '') { return ''; } $alt = esc_attr($title !== '' ? $title : __('合作伙伴', 'aksrt')); $img_tag = $image !== '' ? '' . $alt . '' : ''; $inner = ''; if ($style_type === 'logo') { if ($img_tag === '') { return ''; } $inner = $img_tag; } elseif ($style_type === 'chip') { if ($img_tag !== '') { $inner .= '' . $img_tag . ''; } $inner .= '' . esc_html($title) . ''; } else { if ($img_tag !== '') { $inner .= '
' . $img_tag . '
'; } $inner .= '
'; if ($title !== '') { $inner .= '
' . esc_html($title) . '
'; } if ($desc !== '') { $inner .= '
' . esc_html($desc) . '
'; } $inner .= '
'; } if ($url !== '') { if ($go_link && function_exists('aksrt_go_link')) { $url = aksrt_go_link($url, true); } $tgt = $target !== '' ? ' target="' . esc_attr($target) . '" rel="noopener noreferrer"' : ''; return '' . $inner . ''; } return '
' . $inner . '
'; } /** * @param array $instance * @return array */ private function resolve_partners(array $instance): array { $source = sanitize_key((string) ($instance['link_type'] ?? 'manual')); if ($source === 'link') { $args = [ 'orderby' => sanitize_key((string) ($instance['link_orderby'] ?? 'name')) ?: 'name', 'order' => strtoupper((string) ($instance['link_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC', 'limit' => max(1, min(100, (int) ($instance['link_limit'] ?? 50))), ]; $cats = $instance['link_cats'] ?? ''; if (is_array($cats)) { $cats = implode(',', array_map('intval', $cats)); } $cats = trim((string) $cats); if ($cats !== '') { $args['category'] = $cats; } $bookmarks = get_bookmarks($args); $out = []; foreach ($bookmarks as $b) { $out[] = [ 'title' => (string) $b->link_name, 'desc' => (string) $b->link_description, 'image' => (string) $b->link_image, 'url' => (string) $b->link_url, 'target' => (string) $b->link_target, ]; } return $out; } return $this->normalize_manual($instance['partners'] ?? []); } /** * @param mixed $raw * @return array */ private function normalize_manual($raw): array { if (is_string($raw)) { $decoded = json_decode($raw, true); $raw = is_array($decoded) ? $decoded : []; } if (!is_array($raw)) { return []; } $out = []; foreach ($raw as $row) { if (!is_array($row)) { continue; } $title = sanitize_text_field((string) ($row['title'] ?? '')); $image = esc_url_raw(trim((string) ($row['image'] ?? ''))); $url = esc_url_raw(trim((string) ($row['url'] ?? $row['link'] ?? ''))); if ($title === '' && $image === '') { continue; } $out[] = [ 'title' => $title, 'desc' => sanitize_text_field((string) ($row['desc'] ?? '')), 'image' => $image, 'url' => $url, 'target' => sanitize_text_field((string) ($row['target'] ?? '_blank')), ]; if (count($out) >= 40) { break; } } return $out; } public function form($instance): void { $title = (string) ($instance['title'] ?? ''); $link_type = (string) ($instance['link_type'] ?? 'manual'); $partners_json = is_string($instance['partners'] ?? null) ? (string) $instance['partners'] : wp_json_encode($this->normalize_manual($instance['partners'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>





render_common_form_section($instance); } public function update($new_instance, $old_instance): array { $business = [ 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), 'link_type' => in_array(($new_instance['link_type'] ?? ''), ['manual', 'link'], true) ? $new_instance['link_type'] : 'manual', 'partners' => $this->normalize_manual($new_instance['partners'] ?? []), 'link_cats' => sanitize_text_field((string) ($new_instance['link_cats'] ?? '')), 'link_limit' => max(1, min(100, (int) ($new_instance['link_limit'] ?? 50))), 'link_orderby' => sanitize_key((string) ($new_instance['link_orderby'] ?? 'name')), 'link_order' => strtoupper((string) ($new_instance['link_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC', 'style_type' => in_array(($new_instance['style_type'] ?? ''), ['card', 'logo', 'chip'], true) ? $new_instance['style_type'] : 'card', 'rows' => max(1, min(4, (int) ($new_instance['rows'] ?? 1))), 'm_rows' => max(1, min(4, (int) ($new_instance['m_rows'] ?? 1))), 'card_width' => max(60, min(400, (int) ($new_instance['card_width'] ?? 220))), 'card_height' => max(40, min(200, (int) ($new_instance['card_height'] ?? 90))), 'card_radius' => max(0, min(40, (int) ($new_instance['card_radius'] ?? 10))), 'speed' => max(1, min(20, (int) ($new_instance['speed'] ?? 3))), 'direction' => in_array(($new_instance['direction'] ?? ''), ['alternate', 'left', 'right'], true) ? $new_instance['direction'] : 'alternate', 'pause_hover' => !empty($new_instance['pause_hover']) ? 1 : 0, 'card_bg' => !empty($new_instance['card_bg']) ? 1 : 0, 'end_fade' => !empty($new_instance['end_fade']) ? 1 : 0, 'go_link' => !empty($new_instance['go_link']) ? 1 : 0, 'show_widget_bg' => !empty($new_instance['show_widget_bg']) ? 1 : 0, ]; return $this->update_common_fields($new_instance, $old_instance, $business); } }