| 1 |
<?php |
| 2 |
/** |
| 3 |
* Product FAQ list rendered on single WooCommerce product pages. |
| 4 |
* |
| 5 |
* Mirrors views/shortcodes/faq.php but pulls terms from BOTH the general and |
| 6 |
* product FAQ taxonomies (group IDs are globally unique), and reuses the shared |
| 7 |
* faq-term-title / faq-list parts so the markup and styles match the shortcode. |
| 8 |
* |
| 9 |
* @var int[] $group_ids Resolved FAQ group term IDs to display. |
| 10 |
* @var string $layout Layout class (layout-1..3; layout-4/Retro is not |
| 11 |
* offered for product FAQs). |
| 12 |
* @var bool $enable_schema Whether to emit FAQPage JSON-LD. |
| 13 |
* @var \WPDeveloper\BetterDocs\Utils\Views $view_object |
| 14 |
*/ |
| 15 |
|
| 16 |
if ( ! defined( 'ABSPATH' ) ) { |
| 17 |
exit; |
| 18 |
} |
| 19 |
|
| 20 |
if ( empty( $group_ids ) ) { |
| 21 |
return; |
| 22 |
} |
| 23 |
|
| 24 |
// Respect the FAQ Builder's ordering preference (manual drag-drop by default), |
| 25 |
// mirroring the regular FAQ shortcode instead of a hardcoded alphabetical sort. |
| 26 |
$terms = get_terms( array_merge( |
| 27 |
[ |
| 28 |
'taxonomy' => [ 'betterdocs_faq_category', 'betterdocs_product_faq_category' ], |
| 29 |
'include' => $group_ids, |
| 30 |
'hide_empty' => false, |
| 31 |
], |
| 32 |
betterdocs()->query->faq_terms_order_clause() |
| 33 |
) ); |
| 34 |
|
| 35 |
if ( is_wp_error( $terms ) || empty( $terms ) ) { |
| 36 |
return; |
| 37 |
} |
| 38 |
|
| 39 |
// Mirror the FAQ block/shortcode wrapper classes so the saved layout actually |
| 40 |
// applies: `layout-classic`/`layout-modern` drives Classic vs Modern styling and |
| 41 |
// `betterdocs-faq-<layout>` drives the Abstract (layout-3) styles. Passing the |
| 42 |
// raw "layout-3" alone matched no CSS, so every layout looked the same. |
| 43 |
$layout_variant = ( 'layout-2' === $layout ) ? 'layout-classic' : 'layout-modern'; |
| 44 |
$wrapper_class = trim( |
| 45 |
'betterdocs-faq-wrapper betterdocs-woo-product-faq ' . $layout_variant |
| 46 |
. ' betterdocs-faq-' . esc_attr( $layout ) . ' icon-after' |
| 47 |
); |
| 48 |
?> |
| 49 |
<div class="<?php echo esc_attr( $wrapper_class ); ?>"> |
| 50 |
<div class="betterdocs-faq-inner-wrapper"> |
| 51 |
<?php |
| 52 |
// Group Title Tag is driven by the "Product FAQ for WooCommerce" |
| 53 |
// customizer control so the heading element is configurable. |
| 54 |
$faq_group_title_tag = get_theme_mod( 'betterdocs_faq_group_title_tag_woo', 'h3' ); |
| 55 |
|
| 56 |
$faq_json = ''; |
| 57 |
if ( $enable_schema ) { |
| 58 |
$faq_json = [ |
| 59 |
'@context' => 'https://schema.org', |
| 60 |
'@type' => 'FAQPage', |
| 61 |
'mainEntity' => [], |
| 62 |
]; |
| 63 |
|
| 64 |
$GLOBALS['betterdocs_faq_schema_main_entity'] = []; |
| 65 |
} |
| 66 |
|
| 67 |
foreach ( $terms as $term ) { |
| 68 |
// Skip groups with no *published* FAQs. $term->count can include |
| 69 |
// drafts/other statuses, which would render the group title above an |
| 70 |
// empty "no FAQ" body. The display query is publish-only, so gate on |
| 71 |
// it directly. |
| 72 |
$faqs = betterdocs()->query->get_faq_by_term( $term->term_id, $term->taxonomy ); |
| 73 |
$has_published = $faqs->have_posts(); |
| 74 |
wp_reset_postdata(); |
| 75 |
if ( ! $has_published ) { |
| 76 |
continue; |
| 77 |
} |
| 78 |
|
| 79 |
$view_object->get( 'shortcode-parts/faq-term-title', [ |
| 80 |
'title' => $term->name, |
| 81 |
'faq_group_title_tag' => $faq_group_title_tag, |
| 82 |
] ); |
| 83 |
|
| 84 |
$view_object->get( 'shortcode-parts/faq-list', [ |
| 85 |
'term' => $term, |
| 86 |
'faq_schema' => $enable_schema, |
| 87 |
'faq_json' => $enable_schema ? $faq_json['mainEntity'] : '', |
| 88 |
] ); |
| 89 |
} |
| 90 |
|
| 91 |
if ( $enable_schema ) { |
| 92 |
$faq_json['mainEntity'] = $GLOBALS['betterdocs_faq_schema_main_entity']; |
| 93 |
echo '<script type="application/ld+json">' . wp_json_encode( $faq_json ) . '</script>'; |
| 94 |
} |
| 95 |
?> |
| 96 |
</div> |
| 97 |
</div> |
| 98 |
|