WordPress.org

Making WordPress.org

Changeset 8899


Ignore:
Timestamp:
05/30/2019 10:11:34 PM (15 months ago)
Author:
coffee2code
Message:

Handbook plugin: Prevent duplicate anchors when generating table of contents links from heading tags.

Previously, if text for a heading was used more than once in the page, the same anchor would be created for each heading, making the second (and subsequent) duplicates untargetable and the toc links would all point to the first instance.

Fixes #4406.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/handbook/inc/table-of-contents.php

    r7994 r8899  
    8989            $toc .= "<$contents_header>" . esc_html( $this->args->header_text ) . "</$contents_header><ul class=\"items\">";
    9090            $last_item = false;
     91            $used_ids = [];
     92
    9193            foreach ( $items as $item ) {
    9294                if ( $last_item ) {
     
    100102
    101103                $last_item = $item[2];
    102                 $toc .= '<li><a href="#' . sanitize_title_with_dashes($item[3])  . '">' . $item[3]  . '</a>';
     104
     105                $id = sanitize_title_with_dashes( $item[3] );
     106                // Append unique suffix if anchor ID isn't unique.
     107                $count = 2;
     108                $orig_id = $id;
     109                while ( in_array( $id, $used_ids ) && $count < 50 ) {
     110                    $id = $orig_id . '-' . $count;
     111                    $count++;
     112                }
     113                $used_ids[] = $id;
     114
     115                $toc .= '<li><a href="#' . esc_attr( $id  ) . '">' . $item[3]  . '</a>';
    103116            }
    104117            $toc .= "</ul>\n</div>\n";
     
    113126        $matches = array();
    114127        $replacements = array();
     128        $used_ids = array();
    115129
    116130        foreach ( $items as $item ) {
     
    119133            $id = sanitize_title_with_dashes($item[2]);
    120134
     135            // Append unique suffix if anchor ID isn't unique.
     136            $count = 2;
     137            $orig_id = $id;
     138            while ( in_array( $id, $used_ids ) && $count < 50 ) {
     139                $id = $orig_id . '-' . $count;
     140                $count++;
     141            }
     142            $used_ids[] = $id;
     143       
    121144            if ( ! $first ) {
    122145                $replacement .= '<p class="toc-jump"><a href="#top">' . __( 'Top &uarr;', 'wporg' ) . '</a></p>';
     
    131154
    132155        if ( $replacements ) {
    133             $content = str_replace( $matches, $replacements, $content );
     156            if ( count( array_unique( $matches ) ) !== count( $matches ) ) {
     157                foreach ( $matches as $i => $match ) {
     158                    $content = preg_replace( '/' . preg_quote( $match, '/' ) . '/', $replacements[ $i ], $content, 1 );
     159                }
     160            } else {
     161                $content = str_replace( $matches, $replacements, $content );
     162            }
    134163        }
    135164
Note: See TracChangeset for help on using the changeset viewer.