I’m trying to capture the attributes in a <pre> tag along with an optional class tag. I’d like to capture the contents of the class tag in one regex rather than capture all the attributes and then find the class attribute value if possible. Since the class tag is optional, I’ve tried adding a ? but this causes the following regex to capture only using the last capture group – the class is not captured and neither are the attributes before it.
// Works, but class isn't optional
'(?<!\$)<pre([^\>]*?)(\bclass\s*=\s*(["\'])(.*?)\3)([^\>]*)>'
// Fails to match class, the whole set of attributes are matched by last group
'(?<!\$)<pre([^\>]*?)(\bclass\s*=\s*(["\'])?(.*?)\3)([^\>]*)>'
e.g. <pre style="..." class="some-class" title="stuff">
EDIT:
I ended up using this:
$wp_content = preg_replace_callback('#(?<!\$)<\s*pre(?=(?:([^>]*)\bclass\s*=\s*(["\'])(.*?)\2([^>]*))?)([^>]*)>(.*?)<\s*/\s*pre\s*>#msi', 'CrayonWP::pre_tag', $wp_content);
It allows whitespace within the tag and also separates the stuff before and after the class attribute as well as capturing all attributes.
Then the callback puts things in place:
public static function pre_tag($matches) {
$pre_class = $matches[1];
$quotes = $matches[2];
$class = $matches[3];
$post_class = $matches[4];
$atts = $matches[5];
$content = $matches[6];
if (!empty($class)) {
// Allow hyphenated "setting-value" style settings in the class attribute
$class = preg_replace('#\b([A-Za-z-]+)-(\S+)#msi', '$1='.$quotes.'$2'.$quotes, $class);
return "[crayon $pre_class $class $post_class] $content [/crayon]";
} else {
return "[crayon $atts] $content [/crayon]";
}
}
You could put the capturing group for the
classattribute in a lookahead assertion and make it optional:Now,
$2will contain theclassattribute’s value if it is present.