kieranstartup kieranstartup - 1 month ago 7
PHP Question

Replacing multiple href values using a regular expression in PHP

I know this question has more of a WordPress background to it, but I'm hoping it's just my lack of PHP knowledge that is the problem here.

I have a regex that looks for

<a>
tags such as:
<a href="http://website.co.uk/post/post-title">Find Out More</a>
, which are generated from content inputted by the user. Once it finds this content a
foreach
loop runs over the matched text and uses a WordPress function
$postId = url_to_postid( $url );
to convert the URL into a PostID.

This is an example output:
<a href="#171">Find Out More</a>
.

This works fine as long as there is one link in each piece of matched text. However if there are two or more links, it sets every link to have the same
href
which is incorrect.

I'm sure this is something to do with how I've got my loop running. The code I'm using is below:

<?php
$string = get_field('sample_text_box');
$pattern = "/(?<=href=(\"|'))[^\"']+(?=(\"|'))/";
preg_match_all($pattern, $string, $matches);
$urls = $matches[0];

foreach($urls as $key => $url) {
$postId[$key] = url_to_postid( $url );
}

$newstring = preg_replace($pattern , $postId[$key] , $string);
echo $newstring;
?>


The line
get_field('sample_text_box');
is an Advanced Custom Field function which "returns the value of the specified field". You can read about it here if it helps: https://www.advancedcustomfields.com/resources/get_field/

Thanks!

Answer

The problem with your code is that you are indeed replacing the pattern with a single value of $postId[$key], where $key is the last value assigned in foreach.

You also can not pass $postId instead because preg_replace expects both pattern and replacement be of the same type - whether strings, or arrays.

However, the problem is easily solved with preg_replace_callback function:

$pattern = '/(?<=href\="|\')([^"\']+)(?="|\')/m';

$new_string = preg_replace_callback($pattern, function ($matches) {
  return isset($matches[1]) ? url_to_postid($matches[1]) : $matches[0];
}, $string);