Code executes outside of Loop while same code gives ‘Uninitialized string offset’ notice inside a while loop

That error means you’re attempting to address a string or null as if it were an array. Perhaps it’s returning fewer than 5 matches, in which case $array[0][4] would be unset.

Here’s your problem:

function thing($content) {

preg_match_all("/(<h[^>]*>.*?<\/h2>\n*<p>.*?<\/p>)/", $content, $array);

$i = 1;
$limit = count($array[0]);

$array = $array[0][4]; // you've overwritten $array with what used to be $array[0][4]
echo $array; //outside loop

while ( $i <= $limit) {
  $array = $array[0][4]; // now you're trying to overwrite $array again once for every time you go around the loop
  echo $array; inside loop
  $i++;
}
return $content;
}
add_action('the_content', 'thing', 50);

Let’s rewrite it a bit:

function thing($content) {

preg_match_all("/(<h[^>]*>.*?<\/h2>\n*<p>.*?<\/p>)/", $content, $array);

$i = 1;
$limit = count($array[0]);

echo $array[0][4]; //outside loop

while ( $i <= $limit) {
  echo $array[0][4]; // inside loop
  $i++;
}
return $content;
}
add_action('the_content', 'thing', 50);

This still isn’t great code as it assumes the array is 5 members and repeats the same value each time it loops. Let’s rewrite the while loop into a for:

for( $i = 0; $i < $limit; $i++ ) {
  echo $array[0][$i]; // inside loop
}