phpreplaceforeach

How can I return Wordpress content with generated ID's based on the number of H2 tags


What I'm trying to do it make a code where all H2 tags from the_content are pulled and read out to create a table of content. I've done this succesfully with the code below:

function h2s_in_the_content($content) {
    if (preg_match_all('#<h2>(.*?)</h2>#', $content, $matches)) {
        foreach ($matches[1] as $key => $value) {
            
            echo '<li class="inhoudsopgave-li">';
            echo '<a href="#' . $key . '" class="link white">' . $value . '</a>';
            echo '</li>';
        }
    }
}

add_filter('the_content', 'h2s_in_the_content', 98);

The output is like the picture below where all H2's are pulled and converted to links. Picture of the table of contents with pulled H2's

The problem I'm encountering is that I want to fetch the_content, read and replace all H2's on the same way as above and return them with the $key variable which should output this: <h2 id="0/1/2/3/etc.">. I'm using this code to try and do that:

function replace_text_wps($content){
    if (preg_match_all('#<h2>(.*?)</h2>#', $content, $matches)) {
        foreach ($matches[1] as $key => $value) {
            $replace = array(
                '<h2>' => '<h2 id="' . $key . '">'
            );
        return $content;
        }
    }
    $content = str_replace(array_keys($replace), $replace, $content);
    return $content;
}

add_filter('the_content', 'replace_text_wps',99);

The code is somewhat successful, but the problem is that all H2's are returned with id="2" instead of 0/1/2/3/etc. See the image below of the source code.

enter image description here

What is wrong in my code and how can I make it so that it counts each H2 and returns the id based on the number of the H2 encountered. It works in the first example where the H2's are pulled and changed to links but not in the second example..

Thanks a lot for helping!


Solution

  • If you want to do a custom replacement, you could keep track of the number of times the function is triggered, and use preg_replace_callback:

    $html = <<<HTML
    This is <h2>H2 nummer 1</h2>
    and this is This is <h2>H2 nummer 2</h2>
    This is <h2>H2 nummer 3</h2>
    HTML;
    
    function replace_text_wps($content)
    {
    
        return preg_replace_callback('#<h2>(.*?)</h2>#', function ($m) {
            static $h2Count = 0;
            return sprintf('<h2 id="%s">%s</h2>', ++$h2Count, $m[1]);
        }, $content);
    }
    
    echo replace_text_wps($html);
    

    Output

    This is <h2 id="1">H2 nummer 1</h2>
    and this is This is <h2 id="2">H2 nummer 2</h2>
    This is <h2 id="3">H2 nummer 3</h2>
    

    See a PHP demo.