Skip to content

Commit 9f5bcb2

Browse files
committed
Adding SimpleTOC_Headline_Ids class to ensure there are no duplicate Ids.
1 parent 1e24327 commit 9f5bcb2

File tree

1 file changed

+75
-10
lines changed

1 file changed

+75
-10
lines changed

plugin.php

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Plugin Name: SimpleTOC - Table of Contents Block
55
* Plugin URI: https://marc.tv/simpletoc-wordpress-inhaltsverzeichnis-plugin-gutenberg/
66
* Description: SEO-friendly Table of Contents Gutenberg block. No JavaScript and no CSS means faster loading.
7-
* Version: 6.9.2
7+
* Version: 6.9.1
88
* Author: Marc Tönsing
99
* Author URI: https://toensing.com
1010
* Text Domain: simpletoc
@@ -127,6 +127,68 @@ function register_simpletoc_block()
127127
return $toc_plugins;
128128
});
129129

130+
/**
131+
* Class to manage headline IDs.
132+
*
133+
* Ensures a unique anchor for each headline.
134+
*/
135+
class SimpleTOC_Headline_Ids {
136+
/**
137+
* Array of headlines and their counts.
138+
* @var array
139+
*/
140+
private $headlines = array();
141+
142+
/**
143+
* Add a headline to the array
144+
* @param string $headline_slug The slug of the headline
145+
*/
146+
private function add_headline( $headline_slug ) {
147+
if ( empty( $headline_slug ) ) {
148+
return;
149+
}
150+
151+
if ( ! isset( $this->headlines[ $headline_slug ] ) ) {
152+
$this->headlines[ $headline_slug ] = 1;
153+
} else {
154+
$this->headlines[ $headline_slug ] = $this->get_headline_count( $headline_slug ) + 1;
155+
}
156+
if ( $this->headlines[ $headline_slug ] > 1 ) {
157+
$new_headline_slug = $headline_slug . '-' . $this->headlines[ $headline_slug ];
158+
if ( isset( $this->headlines[ $new_headline_slug ] ) ) {
159+
$new_headline_slug = $this->add_headline( $new_headline_slug );
160+
}
161+
$new_headline_count = $this->get_headline_count( $new_headline_slug );
162+
if ( 0 === $new_headline_count ) {
163+
$new_headline_count = 1;
164+
}
165+
$this->headlines[ $new_headline_slug ] = $new_headline_count;
166+
return $new_headline_slug;
167+
}
168+
return $headline_slug;
169+
}
170+
171+
/**
172+
* Get the anchor for a headline
173+
* @param string $headline The headline
174+
* @return string The anchor for the headline
175+
*/
176+
public function get_headline_anchor( $headline ) {
177+
if ( empty( $headline ) ) {
178+
return '';
179+
}
180+
181+
$headline_slug = simpletoc_sanitize_string( $headline );
182+
183+
$headline_slug = $this->add_headline( $headline_slug );
184+
return $headline_slug;
185+
}
186+
187+
private function get_headline_count( $headline_slug = '' ) {
188+
return $this->headlines[ $headline_slug ] ?? 0;
189+
}
190+
}
191+
130192
/**
131193
* Adds IDs to the headings of the provided post content using a recursive block structure.
132194
* @param string $content The content to add IDs to
@@ -159,18 +221,22 @@ function add_ids_to_blocks_recursive($blocks)
159221
'generateblocks/text',
160222
'generateblocks/headline',
161223
);
162-
224+
163225
/**
164226
* Filter to add supported blocks for IDs.
165227
*
166228
* @param array $supported_blocks The array of supported blocks.
167229
*/
168230
$supported_blocks = apply_filters( 'simpletoc_supported_blocks_for_ids', $supported_blocks );
169231

232+
// Need two separate instances so that IDs aren't double coubnted.
233+
$inner_html_id_instance = new SimpleTOC_Headline_Ids();
234+
$inner_content_id_instance = new SimpleTOC_Headline_Ids();
235+
170236
foreach ($blocks as &$block) {
171237
if (isset($block['blockName']) && in_array( $block['blockName'], $supported_blocks ) && isset($block['innerHTML']) && isset($block['innerContent']) && isset($block['innerContent'][0])) {
172-
$block['innerHTML'] = add_anchor_attribute($block['innerHTML']);
173-
$block['innerContent'][0] = add_anchor_attribute($block['innerContent'][0]);
238+
$block['innerHTML'] = add_anchor_attribute( $block['innerHTML'], $inner_html_id_instance );
239+
$block['innerContent'][0] = add_anchor_attribute( $block['innerContent'][0], $inner_content_id_instance );
174240
} elseif (isset($block['attrs']['ref'])) {
175241
// search in reusable blocks (this is not finished because I ran out of ideas.)
176242
// $reusable_block_id = $block['attrs']['ref'];
@@ -396,9 +462,10 @@ function simpletoc_plugin_meta($links, $file)
396462
/**
397463
* Adds an ID attribute to all Heading tags in the provided HTML.
398464
* @param string $html The HTML content to modify
465+
* @param SimpleTOC_Headline_Ids $headline_class_instance The instance of the SimpleTOC_Headline_Ids class
399466
* @return string The modified HTML content with ID attributes added to the Heading tags
400467
*/
401-
function add_anchor_attribute($html)
468+
function add_anchor_attribute($html, $headline_class_instance = null)
402469
{
403470

404471
// remove non-breaking space entites from input HTML
@@ -425,7 +492,7 @@ function add_anchor_attribute($html)
425492
}
426493
// Set id attribute
427494
$heading_text = trim(strip_tags($html));
428-
$anchor = simpletoc_sanitize_string($heading_text);
495+
$anchor = $headline_class_instance->get_headline_anchor($heading_text);
429496
$tag->setAttribute("id", $anchor);
430497
}
431498

@@ -456,17 +523,15 @@ function generate_toc($headings, $attributes)
456523
list($min_depth, $initial_depth) = find_min_depth($headings, $attributes);
457524

458525
$item_count = 0;
459-
526+
$headline_ids = new SimpleTOC_Headline_Ids();
460527
foreach ($headings as $line => $headline) {
461528
$this_depth = (int)$headings[$line][2];
462529
$next_depth = isset($headings[$line + 1][2]) ? (int)$headings[$line + 1][2] : '';
463530
$exclude_headline = should_exclude_headline($headline, $attributes, $this_depth);
464531
$title = trim(strip_tags($headline));
465532
$customId = extract_id($headline);
466-
$link = $customId ? $customId : simpletoc_sanitize_string($title);
467-
533+
$link = $customId ? $customId : $headline_ids->get_headline_anchor($title );
468534
if (!$exclude_headline) {
469-
470535
$item_count++;
471536
open_list($list, $list_type, $min_depth, $this_depth);
472537
$page = get_page_number_from_headline($headline);

0 commit comments

Comments
 (0)