' . "\n" . '
'; $main_close = '
' . "\n" . ''; $header = ''; $footer = ''; register_block_template('sahcs//single-' . SAHCS_CPT, [ 'title' => __('Single Case Study', 'siteaudithub-case-studies'), 'description' => __('Shows one case study with its hero, table of contents and sections.', 'siteaudithub-case-studies'), 'content' => $header . "\n" . $main_open . '' . $main_close . "\n" . $footer, 'post_types' => [SAHCS_CPT], ]); register_block_template('sahcs//archive-' . SAHCS_CPT, [ 'title' => __('Case Studies Listing', 'siteaudithub-case-studies'), 'description' => __('The main case studies page with category filters.', 'siteaudithub-case-studies'), 'content' => $header . "\n" . $main_open . '' . $main_close . "\n" . $footer, ]); register_block_template('sahcs//taxonomy-' . SAHCS_TAX, [ 'title' => __('Case Study Category', 'siteaudithub-case-studies'), 'description' => __('Case studies from one category.', 'siteaudithub-case-studies'), 'content' => $header . "\n" . $main_open . '' . $main_close . "\n" . $footer, ]); }, 20); /* ------------------------------------------------------------------ * Single case study layout + table of contents * ---------------------------------------------------------------- */ /** Marks the end of the hero so the layout can place it above the body. */ add_filter('render_block_sahcs/hero', function ($html) { return $html === '' ? $html : $html . ''; }); add_filter('the_content', 'sahcs_single_layout', 20); function sahcs_single_layout($content) { if (is_admin() || !is_singular(SAHCS_CPT) || sahcs_is_embedded()) { return $content; } if ((int) get_the_ID() !== (int) get_queried_object_id()) { return $content; } if (sahcs_uses_page_builder(get_the_ID())) { return $content; // the page builder's own design is shown as made } // SEO plugins (Rank Math, Yoast…) and some themes run the_content inside // or for excerpts. Those copies are never shown, so leave them // alone and lay out only the content that is printed on the page. if (doing_action('wp_head') || doing_filter('get_the_excerpt') || doing_filter('wp_trim_excerpt') || doing_filter('the_excerpt')) { return $content; } if (strpos($content, 'sahcs-single"') !== false) { return $content; // already laid out } $hero = ''; $body = $content; $marker = ''; $pos = strpos($content, $marker); if ($pos !== false) { $hero = substr($content, 0, $pos); $body = substr($content, $pos + strlen($marker)); } else { // No Hero block in this case study: add a default one so the page // always has its title (H1), categories and featured image. $hero = str_replace($marker, '', render_block([ 'blockName' => 'sahcs/hero', 'attrs' => [], 'innerBlocks' => [], 'innerHTML' => '', 'innerContent' => [], ])); } $toc = ''; // SEO: the case study title in the hero is the page's only H1. Any H1 // typed into the sections becomes an H2, so the outline stays clean. $body = preg_replace(['#)#i', '##i'], [''], $body); if (sahcs_toc_enabled_for(get_the_ID())) { $result = sahcs_build_toc($body); $body = $result['html']; $toc = $result['toc']; } $out = '
' . sahcs_page_script(); $out .= $hero; $out .= '
'; if ($toc !== '') { $out .= ''; } $out .= '
' . $body . '
'; $out .= '
'; return $out; } function sahcs_toc_enabled_for($post_id) { $mode = get_post_meta($post_id, '_sahcs_toc', true); if ($mode === 'on') { return true; } if ($mode === 'off') { return false; } return (bool) sahcs_get_settings('toc_enabled'); } /** * Adds ids to H2 (and H3) headings that don't have one, and builds the * table of contents from them. */ function sahcs_build_toc($html) { $depth = sahcs_get_settings('toc_depth') === 'h2' ? 'h2' : 'h2|h3'; $skip_classes = ['sahcs-card__title', 'sahcs-faq__qtext', 'sahcs-related__title', 'sahcs-grid-wrap__title', 'sahcs-toc-skip']; $items = []; $used = []; // Ids already in the content (from sections or the author) are taken. if (preg_match_all('/\sid=("|\')([^"\']+)\1/i', $html, $all)) { foreach ($all[2] as $existing) { $used[$existing] = true; } } $html = preg_replace_callback('#<(' . $depth . ')\b([^>]*)>(.*?)#is', function ($m) use (&$items, &$used, $skip_classes) { $attrs = $m[2]; foreach ($skip_classes as $c) { if (strpos($attrs, $c) !== false) { return $m[0]; } } $text = sahcs_trim(wp_strip_all_tags($m[3])); if ($text === '') { return $m[0]; } if (preg_match('/\sid=("|\')([^"\']+)\1/i', $attrs, $idm)) { $id = $idm[2]; unset($used[$id]); // reset so the duplicate check below doesn't trip on itself } else { $base = sanitize_title($text); $base = $base !== '' ? $base : 'section'; $id = $base; $n = 2; while (isset($used[$id])) { $id = $base . '-' . $n; $n++; } $attrs .= ' id="' . esc_attr($id) . '"'; } $used[$id] = true; $items[] = ['level' => strtolower($m[1]), 'id' => $id, 'text' => $text]; return '<' . $m[1] . $attrs . '>' . $m[3] . ''; }, $html); $min = max(1, (int) sahcs_get_settings('toc_min')); $h2_count = count(array_filter($items, function ($i) { return $i['level'] === 'h2'; })); if ($h2_count < $min) { return ['html' => $html, 'toc' => '']; } $title = sahcs_get_settings('toc_title'); $title = $title !== '' ? $title : __('On this page', 'siteaudithub-case-studies'); $toc = '
'; $toc .= '' . esc_html($title) . ''; $toc .= '
'; return ['html' => $html, 'toc' => $toc]; }