You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

419 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
/**
* FAQ 区块模板
* 显示常见问题和答案,支持手风琴折叠效果
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 获取短代码参数
global $faq_shortcode_atts;
$id = isset($faq_shortcode_atts['id']) ? $faq_shortcode_atts['id'] : 'nenghui-faq';
$class = isset($faq_shortcode_atts['class']) ? $faq_shortcode_atts['class'] : '';
$title = isset($faq_shortcode_atts['title']) ? $faq_shortcode_atts['title'] : 'Frequently Asked Questions';
$posts_per_page = isset($faq_shortcode_atts['posts_per_page']) ? $faq_shortcode_atts['posts_per_page'] : '-1';
$order_by = isset($faq_shortcode_atts['order_by']) ? $faq_shortcode_atts['order_by'] : 'menu_order';
$order = isset($faq_shortcode_atts['order']) ? $faq_shortcode_atts['order'] : 'ASC';
$show_animation = isset($faq_shortcode_atts['show_animation']) ? $faq_shortcode_atts['show_animation'] : 'true';
// 构建查询参数
$query_args = array(
'post_type' => 'faq',
'post_status' => 'publish',
'posts_per_page' => intval($posts_per_page),
'orderby' => $order_by,
'order' => $order
);
// 执行查询
$faq_query = new WP_Query($query_args);
// 生成唯一ID
$unique_id = $id . '-' . uniqid();
?>
<section id="<?php echo esc_attr($unique_id); ?>" class="faq-section <?php echo esc_attr($class); ?>">
<div class="faq-container">
<?php if (!empty($title)): ?>
<div class="faq-header">
<h2 class="faq-title"><?php echo esc_html($title); ?></h2>
</div>
<?php endif; ?>
<?php if ($faq_query->have_posts()): ?>
<div class="faq-accordion">
<?php
$item_index = 0;
while ($faq_query->have_posts()):
$faq_query->the_post();
$item_index++;
$item_id = $unique_id . '-item-' . $item_index;
?>
<div class="faq-item" data-aos="<?php echo $show_animation === 'true' ? 'fade-up' : ''; ?>" data-aos-delay="<?php echo $item_index * 100; ?>">
<div class="faq-question" data-target="<?php echo esc_attr($item_id); ?>">
<h3 class="faq-question-title"><?php the_title(); ?></h3>
<span class="faq-toggle-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="faq-icon-horizontal" d="M12 5V19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path class="faq-icon-vertical" d="M5 12H19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
</div>
<div class="faq-answer" id="<?php echo esc_attr($item_id); ?>">
<div class="faq-answer-content">
<?php
// 显示内容,如果没有内容则显示摘要
$content = get_the_content();
if (!empty($content)) {
echo apply_filters('the_content', $content);
} else {
echo '<p>' . get_the_excerpt() . '</p>';
}
?>
</div>
</div>
</div>
<?php endwhile; ?>
</div>
<?php else: ?>
<div class="faq-no-content">
<p>暂无FAQ内容。</p>
</div>
<?php endif; ?>
</div>
</section>
<?php wp_reset_postdata(); ?>
<style>
.faq-section {
padding: 80px 0;
background-color: #f8f9fa;
}
.faq-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.faq-header {
text-align: center;
margin-bottom: 60px;
}
.faq-title {
font-size: 2.5rem;
font-weight: 700;
color: #333333;
margin: 0;
position: relative;
}
.faq-title::after {
content: '';
position: absolute;
bottom: -15px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 4px;
background: linear-gradient(135deg, #2cb5a9, #00699f);
border-radius: 2px;
}
.faq-accordion {
max-width: 900px;
margin: 0 auto;
}
.faq-item {
margin-bottom: 20px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
background: #ffffff;
transition: all 0.3s ease;
}
.faq-item:hover {
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
transform: translateY(-2px);
transition: all 0.3s ease;
}
.faq-question {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
padding: 25px 30px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.3s ease;
position: relative;
}
.faq-question:hover {
background-image: url('<?php echo get_template_directory_uri(); ?>/assets/images/faq-title-bg.webp');
}
.faq-item.active .faq-question {
background-image: url('<?php echo get_template_directory_uri(); ?>/assets/images/faq-title-bg.webp');
}
.faq-question::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
transition: all 0.3s ease;
}
.faq-question:hover::before {
background: rgba(0, 86, 179, 0.9);
transition: all 0.3s ease;
}
.faq-question-title {
font-size: 1.2rem;
font-weight: 600;
color: #000000;
margin: 0;
flex: 1;
position: relative;
z-index: 1;
line-height: 1.4;
transition: all 0.3s ease;
}
.faq-question:hover .faq-question-title,
.faq-item.active .faq-question .faq-question-title {
color: #ffffff;
}
.faq-toggle-icon {
width: 24px;
height: 24px;
color: #000000;
transition: transform 0.3s ease, color 0.3s ease;
position: relative;
z-index: 1;
flex-shrink: 0;
margin-left: 20px;
}
.faq-question:hover .faq-toggle-icon,
.faq-item.active .faq-question .faq-toggle-icon {
color: #ffffff;
}
.faq-item.active .faq-toggle-icon {
transform: rotate(45deg);
}
.faq-answer {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease, padding 0.4s ease;
background: #ffffff;
}
.faq-item.active .faq-answer {
max-height: 1000px;
padding: 30px;
}
.faq-answer-content {
color: #555555;
line-height: 1.7;
font-size: 1rem;
}
.faq-answer-content p {
margin: 0 0 15px 0;
}
.faq-answer-content p:last-child {
margin-bottom: 0;
}
.faq-answer-content ul,
.faq-answer-content ol {
margin: 15px 0;
padding-left: 25px;
}
.faq-answer-content li {
margin-bottom: 8px;
}
.faq-answer-content strong {
color: #333333;
font-weight: 600;
}
.faq-answer-content a {
color: #007bff;
text-decoration: none;
transition: color 0.3s ease;
}
.faq-answer-content a:hover {
color: #0056b3;
text-decoration: underline;
transition: all 0.3s ease;
}
.faq-no-content {
text-align: center;
padding: 60px 20px;
color: #666666;
font-size: 1.1rem;
}
/* 响应式设计 */
@media (max-width: 768px) {
.faq-section {
padding: 60px 0;
}
.faq-container {
padding: 0 15px;
}
.faq-title {
font-size: 2rem;
}
.faq-header {
margin-bottom: 40px;
}
.faq-question {
padding: 20px;
}
.faq-question-title {
font-size: 1.1rem;
}
.faq-toggle-icon {
margin-left: 15px;
}
.faq-item.active .faq-answer {
padding: 20px;
}
.faq-answer-content {
font-size: 0.95rem;
}
}
@media (max-width: 480px) {
.faq-title {
font-size: 1.8rem;
}
.faq-question {
padding: 18px 15px;
}
.faq-question-title {
font-size: 1rem;
}
.faq-item.active .faq-answer {
padding: 15px;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const faqSection = document.getElementById('<?php echo esc_js($unique_id); ?>');
if (!faqSection) return;
const faqQuestions = faqSection.querySelectorAll('.faq-question');
faqQuestions.forEach(function(question) {
question.addEventListener('click', function() {
const targetId = this.getAttribute('data-target');
const faqItem = this.closest('.faq-item');
const answer = document.getElementById(targetId);
if (!answer || !faqItem) return;
// 切换当前项目的状态
const isActive = faqItem.classList.contains('active');
// 关闭所有其他项目
faqSection.querySelectorAll('.faq-item.active').forEach(function(activeItem) {
if (activeItem !== faqItem) {
activeItem.classList.remove('active');
}
});
// 切换当前项目
if (isActive) {
faqItem.classList.remove('active');
} else {
faqItem.classList.add('active');
}
});
});
// 键盘导航支持
faqQuestions.forEach(function(question, index) {
question.setAttribute('tabindex', '0');
question.setAttribute('role', 'button');
question.setAttribute('aria-expanded', 'false');
question.addEventListener('keydown', function(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.click();
}
});
});
// 更新aria-expanded属性
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
const faqItem = mutation.target;
const question = faqItem.querySelector('.faq-question');
if (question) {
const isActive = faqItem.classList.contains('active');
question.setAttribute('aria-expanded', isActive.toString());
}
}
});
});
faqSection.querySelectorAll('.faq-item').forEach(function(item) {
observer.observe(item, { attributes: true, attributeFilter: ['class'] });
});
});
</script>
<?php if ($show_animation === 'true'): ?>
<script>
// 如果AOS库可用初始化动画
if (typeof AOS !== 'undefined') {
AOS.init({
duration: 800,
easing: 'ease-out-cubic',
once: true,
offset: 100
});
}
</script>
<?php endif; ?>