PluginProbe
SimpleTOC – Table of Contents Block / 7.4.1
SimpleTOC – Table of Contents Block v7.4.1
7.4.1 7.4.0 7.3.1 7.2.0 7.3.0 7.1.1 7.1.0 7.0.10 7.0.9 7.0.8 7.0.7 7.0.6 7.0.4 7.0.5 5.0.21.1 5.0.22 5.0.23 5.0.24 5.0.25 5.0.25.1 5.0.27 5.0.28 5.0.29 5.0.3 5.0.30 All 162 releases
← All changes | plugin.php +52 -30 7.1.1 → 7.4.1 View file →
@@ -2,9 +2,9 @@
2 2 /**
3 3 * Plugin Name: SimpleTOC - Table of Contents Block
4 4 * Plugin URI: https://marc.tv/simpletoc-wordpress-inhaltsverzeichnis-plugin-gutenberg/
5 5 * Description: SEO-friendly Table of Contents Gutenberg block. No JavaScript or CSS by default.
6 - * Version: 7.1.1
6 + * Version: 7.4.1
7 7 * Requires at least: 6.2
8 8 * Requires PHP: 7.3
9 9 * Author: Marc Tönsing
10 10 * Author URI: https://toensing.com
@@ -20,9 +20,9 @@
20 20 require_once __DIR__ . '/simpletoc-admin-settings.php';
21 21 require_once __DIR__ . '/simpletoc-class-headline-ids.php';
22 22
23 23 const DEFAULT_BOX_COLOR = '#ebebeb';
24 -const SIMPLETOC_VERSION = '7.1.1';
24 +const SIMPLETOC_VERSION = '7.4.1';
25 25
26 26 /**
27 27 * Prevents direct execution of the plugin file.
28 28 * If a WordPress function does not exist, it means that the file has not been run by WordPress.
@@ -57,9 +57,10 @@
57 57 wp_add_inline_script(
58 58 'simpletoc-toc-editor-script',
59 59 'window.simpletocEditorSettings = ' . wp_json_encode(
60 60 array(
61 - 'settingsUrl' => admin_url( 'options-general.php?page=simpletoc' ),
61 + 'settingsUrl' => admin_url( 'options-general.php?page=simpletoc' ),
62 + 'scrollSpyEnabled' => simpletoc_scroll_spy_enabled(),
62 63 )
63 64 ) . ';',
64 65 'before'
65 66 );
@@ -77,8 +78,10 @@
77 78 */
78 79 function add_simpletoc_block_editor_settings( $editor_settings, $editor_context ) {
79 80 $editor_settings['simpletocSettingsUrl'] = admin_url( 'options-general.php?page=simpletoc' );
80 81
82 + $editor_settings['simpletocScrollSpyEnabled'] = simpletoc_scroll_spy_enabled();
83 +
81 84 return $editor_settings;
82 85 }
83 86
84 87 add_filter( 'block_editor_settings_all', __NAMESPACE__ . '\add_simpletoc_block_editor_settings', 10, 2 );
@@ -221,9 +224,15 @@
221 224 // Need two separate instances so that IDs aren't double counted.
222 225 $inner_html_id_instance = new SimpleTOC_Headline_Ids();
223 226 $inner_content_id_instance = new SimpleTOC_Headline_Ids();
224 227
228 + $ignored_blocks = simpletoc_get_excluded_blocks();
229 +
225 230 foreach ( $blocks as &$block ) {
231 + if ( isset( $block['blockName'] ) && in_array( $block['blockName'], $ignored_blocks, true ) ) {
232 + continue;
233 + }
234 +
226 235 if ( isset( $block['blockName'] ) && in_array( $block['blockName'], $supported_blocks, true ) && isset( $block['innerHTML'] ) && isset( $block['innerContent'] ) && isset( $block['innerContent'][0] ) ) {
227 236 $block['innerHTML'] = add_anchor_attribute( $block['innerHTML'], $inner_html_id_instance, $block );
228 237 $block['innerContent'][0] = add_anchor_attribute( $block['innerContent'][0], $inner_content_id_instance, $block );
229 238 } elseif ( ! empty( $block['innerBlocks'] ) ) {
@@ -244,21 +253,30 @@
244 253 function render_callback_simpletoc( $attributes ) {
245 254 $is_backend = defined( 'REST_REQUEST' ) && REST_REQUEST && 'edit' === filter_input( INPUT_GET, 'context' );
246 255 $title_text = $attributes['title_text'] ? esc_html( trim( $attributes['title_text'] ) ) : __( 'Table of Contents', 'simpletoc' );
247 256 $alignclass = ! empty( $attributes['align'] ) ? 'align' . $attributes['align'] : '';
248 - $class_name = ! empty( $attributes['className'] ) ? wp_strip_all_tags( $attributes['className'] ) : '';
249 257 $title_level = $attributes['title_level'];
250 258 $global_box_style_enabled = apply_filters( 'simpletoc_box_style_enabled', false ) || true === (bool) get_option( 'simpletoc_box_style_enabled', false );
251 - $box_style_enabled = $global_box_style_enabled || ! empty( $attributes['box_style'] );
259 + $legacy_box_style_enabled = ! empty( $attributes['box_style'] );
260 + $typography_enabled = ! empty( $attributes['fontSize'] ) || ! empty( $attributes['style']['typography'] );
252 261 $wrapper_classes = array( 'simpletoc' );
253 262 $wrapper_style = '';
254 263
255 - if ( $box_style_enabled ) {
264 + if ( simpletoc_scroll_spy_enabled() || ! empty( $attributes['scroll_spy'] ) ) {
265 + $wrapper_classes[] = 'has-simpletoc-scroll-spy';
266 + }
267 +
268 + if ( $typography_enabled ) {
269 + $wrapper_classes[] = 'has-simpletoc-typography';
270 + }
271 +
272 + if ( $global_box_style_enabled || $legacy_box_style_enabled ) {
273 + $wrapper_classes[] = 'is-style-boxed';
256 274 $wrapper_classes[] = 'has-simpletoc-box-style';
257 275
258 276 if ( $global_box_style_enabled ) {
259 277 $wrapper_classes[] = 'has-background';
260 - $wrapper_style = safecss_filter_attr( 'background-color:' . DEFAULT_BOX_COLOR . ';' );
278 + $wrapper_style = safecss_filter_attr( 'background-color:' . DEFAULT_BOX_COLOR . ';' );
261 279 } elseif ( ! empty( $attributes['box_color'] ) ) {
262 280 $wrapper_classes[] = 'has-background';
263 281 $wrapper_style = safecss_filter_attr( 'background-color:' . $attributes['box_color'] . ';' );
264 282 } else {
@@ -266,9 +284,8 @@
266 284 $wrapper_style = safecss_filter_attr( 'background-color:' . DEFAULT_BOX_COLOR . ';' );
267 285 }
268 286 }
269 287
270 - $wrapper_enabled = apply_filters( 'simpletoc_wrapper_enabled', false ) || true === (bool) get_option( 'simpletoc_wrapper_enabled', false ) || true === (bool) get_option( 'simpletoc_accordion_enabled', false );
271 288 $wrapper_attrs = get_block_wrapper_attributes(
272 289 array(
273 290 'class' => implode( ' ', $wrapper_classes ),
274 291 'style' => $wrapper_style,
@@ -273,11 +290,10 @@
273 290 'class' => implode( ' ', $wrapper_classes ),
274 291 'style' => $wrapper_style,
275 292 )
276 293 );
277 - $has_wrapper = ! empty( $class_name ) || $wrapper_enabled || $attributes['accordion'] || $attributes['wrapper'] || $box_style_enabled;
278 - $pre_html = $has_wrapper ? '<div role="navigation" aria-label="' . esc_attr__( 'Table of Contents', 'simpletoc' ) . '" ' . $wrapper_attrs . '>' : '';
279 - $post_html = $has_wrapper ? '</div>' : '';
294 + $pre_html = '<div role="navigation" aria-label="' . esc_attr__( 'Table of Contents', 'simpletoc' ) . '" ' . $wrapper_attrs . '>';
295 + $post_html = '</div>';
280 296
281 297 $post = get_post();
282 298 $blocks = ! is_null( $post ) && ! is_null( $post->post_content ) ? parse_blocks( $post->post_content ) : '';
283 299
@@ -286,17 +302,17 @@
286 302 $headings_clean = array_map( 'trim', $headings );
287 303 $toc_html = generate_toc( $headings_clean, $attributes );
288 304
289 305 if ( empty( $blocks ) ) {
290 - return get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, __( 'No blocks found.', 'simpletoc' ), __( 'Save or update post first.', 'simpletoc' ), $wrapper_attrs, $has_wrapper );
306 + return get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, __( 'No blocks found.', 'simpletoc' ), __( 'Save or update post first.', 'simpletoc' ), $wrapper_attrs );
291 307 }
292 308
293 309 if ( empty( $headings_clean ) ) {
294 - return get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, __( 'No headings found.', 'simpletoc' ), __( 'Save or update post first.', 'simpletoc' ), $wrapper_attrs, $has_wrapper );
310 + return get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, __( 'No headings found.', 'simpletoc' ), __( 'Save or update post first.', 'simpletoc' ), $wrapper_attrs );
295 311 }
296 312
297 313 if ( empty( $toc_html ) ) {
298 - return get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, __( 'No headings found.', 'simpletoc' ), __( 'Check minimal and maximum level block settings.', 'simpletoc' ), $wrapper_attrs, $has_wrapper );
314 + return get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, __( 'No headings found.', 'simpletoc' ), __( 'Check minimal and maximum level block settings.', 'simpletoc' ), $wrapper_attrs );
299 315 }
300 316
301 317 return $pre_html . $toc_html . $post_html;
302 318 }
@@ -310,27 +326,20 @@
310 326 * @param string $alignclass The CSS class for alignment of the Table of Contents block.
311 327 * @param string $title_text The text for the Table of Contents title.
312 328 * @param string $warning_text1 The first part of the warning message to be displayed.
313 329 * @param string $warning_text2 The second part of the warning message to be displayed.
314 - * @param string $wrapper_attrs Wrapper attributes for the optional block wrapper.
315 - * @param bool $has_wrapper Indicates if the wrapper should be rendered.
330 + * @param string $wrapper_attrs Block wrapper attributes.
316 331 *
317 332 * @return string The HTML output for the empty blocks message.
318 333 */
319 -function get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, $warning_text1, $warning_text2, $wrapper_attrs = '', $has_wrapper = false ) {
334 +function get_empty_blocks_message( $is_backend, $attributes, $title_level, $alignclass, $title_text, $warning_text1, $warning_text2, $wrapper_attrs = '' ) {
320 335 $html = '';
321 336
322 337 if ( $is_backend ) {
323 - if ( $has_wrapper ) {
324 - $html .= '<div role="navigation" aria-label="' . esc_attr__( 'Table of Contents', 'simpletoc' ) . '" ' . $wrapper_attrs . '>';
325 - }
326 -
338 + $html .= '<div role="navigation" aria-label="' . esc_attr__( 'Table of Contents', 'simpletoc' ) . '" ' . $wrapper_attrs . '>';
327 339 $html .= sprintf( '<h%d class="%s">%s</h%d>', $title_level, esc_attr( trim( 'simpletoc-title ' . $alignclass ) ), $title_text, $title_level );
328 340 $html .= sprintf( '<p class="components-notice is-warning %s">%s %s</p>', esc_attr( $alignclass ), esc_html( $warning_text1 ), esc_html( $warning_text2 ) );
329 -
330 - if ( $has_wrapper ) {
331 - $html .= '</div>';
332 - }
341 + $html .= '</div>';
333 342 }
334 343
335 344 return $html;
336 345 }
@@ -367,8 +376,22 @@
367 376 return $headings;
368 377 }
369 378
370 379 /**
380 + * Gets blocks excluded from both anchor generation and TOC collection.
381 + *
382 + * Query templates render repeatedly in a different post context.
383 + *
384 + * @return string[] Excluded block names.
385 + */
386 +function simpletoc_get_excluded_blocks() {
387 + return apply_filters(
388 + 'simpletoc_excluded_blocks',
389 + array( 'core/query', 'generateblocks/query-loop', 'generateblocks/query' )
390 + );
391 +}
392 +
393 +/**
371 394 * Return all headings with a recursive walk through all blocks.
372 395 * This includes groups and reusable block with groups within reusable blocks.
373 396 *
374 397 * @param array[] $blocks The blocks to filter headings from.
@@ -381,9 +404,9 @@
381 404 return $arr;
382 405 }
383 406
384 407 // allow developers to ignore specific blocks.
385 - $ignored_blocks = apply_filters( 'simpletoc_excluded_blocks', array() );
408 + $ignored_blocks = simpletoc_get_excluded_blocks();
386 409
387 410 foreach ( $blocks as $inner_block ) {
388 411 if ( is_array( $inner_block ) ) {
389 412 // if block is ignored, skip.
@@ -479,12 +502,11 @@
479 502 $html_wo_nbs = str_replace( '&nbsp;', ' ', $zero_punctuation );
480 503 // remove umlauts and accents.
481 504 $string_without_accents = remove_accents( $html_wo_nbs );
482 505 // Sanitizes a title, replacing whitespace and a few other characters with dashes.
483 - $sanitized_string = sanitize_title_with_dashes( $string_without_accents );
484 - // Encode for use in an url.
485 - $urlencoded = rawurlencode( $sanitized_string );
486 - return $urlencoded;
506 + // Already returns a URL-safe, percent-encoded slug for non-ASCII input, so no
507 + // further rawurlencode() is needed (that would double-encode the string).
508 + return sanitize_title_with_dashes( $string_without_accents );
487 509 }
488 510
489 511 /**
490 512 * Add additional plugin meta links to the SimpleTOC plugin page.