1

I wrote a code which is changing headings h1 to h2 if it's not first heading of that type. It works, but only when I'm using just PHP. If I want to use it on website, which one is using database to output content, that code doesn't work.

I'm using ob_start() before <html> and ob_get_contents() + ob_end_clean() + rest of my code after </html>, so I think that has to be something wrong "catching" content from database, but I'm not sure. I tried to use that code on a website based on WordPress.

My code (I know it isn't probably the best solution, but it works when I'm using it on any website without CMS):

<!DOCTYPE html>
<?php
    ob_start();
?>
<html>
    <head>
        <title>random page</title>
    </head>
    <body>
      <div class="container">
        <div class="row">
          <div class="col-md-5">
            <h1>afdsfdassfdfdsa</h1>
          </div>
        </div>
      </div>
      <h1>sadffsadf afdsfdsa afsdfs?</h1>
      <h1 class="superclass">random text?</h1>
      <div>
          <p>some ending content</p>
      </div>
    </body>
</html>

<?php
    $bufferContent = ob_get_contents();
    ob_end_clean();

    $matchedContent = '';
    $endContent = '';
    $modifiedContent = '';
    $firstHeadingBoolean = true;
    $h1Pattern = array();
    $h1Pattern[0] = '%<h1(.*?)>%';
    $h1Pattern[1] = '%</h1>%';
    $h1Replacement = array();
    $h1Replacement[0] = '<h2$1>';
    $h1Replacement[1] = '</h2>';
    if(preg_match_all('%((.|\n)*?)(<h1.*?>.*?</h1>)%', $bufferContent, $contentMatches)){
        foreach($contentMatches[0] as $matches) {
            $matchedContent .= $matches;
        }
        $endContent = str_replace($matchedContent, '', $bufferContent);

        foreach ($contentMatches[0] as $matches) {
            if(!$firstHeadingBoolean){
                $firstHeadingBoolean = false;
            } else {
                $matches = preg_replace($h1Pattern, $h1Replacement, $matches);
            }
            $modifiedContent .= $matches;
        }
        echo $modifiedContent;
        echo $endContent;
    } else {
        echo $bufferContent;
    }
?>

EDIT: I tried to use solutions from there but nothing has changed: WordPress filter to modify final html output Now, after some testing, I can see it's not working because preg_match_all doesn't work correctly. Anyone has an idea what is wrong with that preg_match_all? I tested that regex pattern inside that in regex101 and on my localhost and everything worked fine. I don't understand, why isn't it working here?

  • 1
    _"I tried to use that code on a website based on WordPress."_ - then you should probably not be using output buffering to begin with. If this is about the content of posts/pages, then you should use the appropriate filter to manipulate only that content, before it gets output. https://developer.wordpress.org/reference/hooks/the_content/ – CBroe Feb 02 '22 at 12:36
  • Yes, in most cases I am doing it in better way than that, but here I can't find other solution. I have to change that headings which are placed in a lot of different modules and almost every of h1 heading is created manually. This website has thousands pages and I want to create a single solution for every page. BTW. Thanks for advice but even if here it isn't best solution, I would like to know, why it doesn't work or even better: how make it to work :D – Rafał Łazarski Feb 02 '22 at 14:43
  • https://stackoverflow.com/questions/772510/wordpress-filter-to-modify-final-html-output has a couple of approaches to capture the full page source code. – CBroe Feb 02 '22 at 14:48
  • Now I think implementation of that output control in my code is correct and I tried to change approach to use ob_start, ob_end_flush, etc. but that changes nothing. I tested code more and now I see there is problem with preg_match_all (see more in "EDIT:" in post). Do you know what can be wrong here? I would be greatful for any advice :D – Rafał Łazarski Feb 07 '22 at 13:59
  • Other than that you appear to have the first headline logic the wrong way around (you start with `$firstHeadingBoolean = true;`, so you want to check if that variable _is_ true, and set it to false then), I can't see what exactly is supposed to be going wrong, at least not with a very simple example: https://3v4l.org/cOm6d – CBroe Feb 07 '22 at 14:04
  • I know that boolean isn't the best way to check if it's not first iteration but it works. I found out that when I used that code where is more html code inside the buffer, preg_match_all doesn't work. I tried that on regex101 and I have that match information: Catastrophic backtracking has been detected and the execution of your expression has been halted. To find out more and what this is, please read the following article: http://www.regular-expressions.info/catastrophic.html – Rafał Łazarski Feb 07 '22 at 14:18

1 Answers1

0

Ok, so that wasn't problem with sql but with regex. To solve that problem I used code like that:

    <?php
ob_start();
?>

<!-- html code -->


    <?php
        
        $bufferContent = ob_get_contents();
        ob_end_clean();
    
        $bufferContent = preg_split("%(?=<h1)%",$bufferContent);
        $i = 0;
        $h1Pattern = array();
        $h1Pattern[0] = '%<h1(.*?)>%';
        $h1Pattern[1] = '%</h1>%';
        $h1Replacement = array();
        $h1Replacement[0] = '<h2$1>';
        $h1Replacement[1] = '</h2>';
        foreach($bufferContent as $bufferElement){
            if(preg_match("%<h1%", $bufferElement)){
                if($i > 0){
                    echo preg_replace($h1Pattern, $h1Replacement, $bufferElement);
                } else {
                    echo $bufferElement;
                    $i++;
                }
            } else {
                echo $bufferElement;
            }
        }
    ?>