0

I'm using str_replace to search and replace some shortcodes as [warning] with an html code <span class="warn_class"> Warning</span> Here is my code

function replace($text) {
    $text = str_replace('[warning]', '<span class="warning_class">Warning </span>', $text); 
}
add_filter('the_content', 'replace');

As I need to explain to users how to use these shortcodes I'm trying to escape replacing the shortcode by using a backslashe before it\[warning]. Here is my new code

function replace($text) {
    $pattern = array();
    $pattern[0]= '[warning]';
    $pattern[1]= '\[warning]';
    $replacement = array();
    $replacement[0] = '<span class="warning_class"> Warning <span>';
    $replacement[1] = '[warning]';
    $text = str_replace($pattern, $replacement, $text);
}
add_filter('the_content', 'replace');

The problem is that all instances of [warning] is being replaced. Any idea to solve this problem?

Hamed
  • 159
  • 8
  • You could avoid using that replacement for the explanation text, or use HTML entities – Nico Haase Mar 12 '19 at 14:28
  • @trincot I got this error message "Only variables can be passed by reference " – Hamed Mar 12 '19 at 14:33
  • @NicoHaase It is a forum site, so some users may have to explain to others how to use these shrotcodes. So I don't think using HTML entities is a good idea – Hamed Mar 12 '19 at 14:38
  • Well, that's something you should have mentioned before: you could write a code that can be used as a wrapper around other text which handles the automatic escaping – Nico Haase Mar 12 '19 at 14:41
  • Sorry, my previous comment was wrong. If you need to replace only the first occurrence, use [this solution](https://stackoverflow.com/a/1252710/5459839) – trincot Mar 12 '19 at 15:01
  • str_replace can also be somewhat surprising: `print str_replace(['a', 'b'], ['b', 'c'], 'a');` results in `c`. – Progrock Mar 12 '19 at 15:50
  • @Progrock Not working. It's replacing all text (not only shortcode) by `c` – Hamed Mar 12 '19 at 16:19

1 Answers1

1

Use preg_replace() in order to replace all specific shortcodes which not have a \ written before.

Then, preg_replace() or str_replace() shortcodes preceded with a \ for removing this one and so showing the original shortcode.

function replace($text) {
    $text = preg_replace('/([^\\\\])\[warning\]/', '$1<span class="warning_class"> Warning <span>', $text);
    $text = str_replace('\\[warning]', '[warning]', $text);

    return $text;
}

echo replace('replaced shortcode: _[warning] ; show original shortcode: \\[warning]');
// Output: replaced shortcode: _ Warning ; show original shortcode: [warning]

The regex contains four backslashes because how strings are handled in PHP. The real regex pattern should be: ([^\\])\[warning\] with:

  • (...) save its content as a reference.
  • [^\\] find a character which is not a \.
  • \[warning\] literally find [warning].

$1 in second parameter is the reference to (...) content (here, it will be the character before the [ of your shortcode if it's not a backslash).

Kévin Bibollet
  • 3,573
  • 1
  • 15
  • 33
  • Thank you! This did the work, however, it moves any other special character (as _ /) that may come just before the shortcode (not a real problem). – Hamed Mar 12 '19 at 15:31
  • One more thing, I've seen that replacing `([^\\\\])` by `(?<!\\\\)` and `\ ` by `\\\\ `is more appropriate. – Hamed Apr 04 '19 at 12:13