0

I am developing a custom post type, which, among others includes the possibility of sending an email from within the post editor. The email body textarea is populated through a custom settings page and saved into a post_meta array which also includes the email and subject. Until here all fine.

The standard email content from the settings page includes %%PROPOSAL_LINK%% and %%PROPOSAL_LINK_URL%% which are supposed to be filtered out and replaced with a html link and a normal link to the permalink of the post where the email has originated from.

The following is the function as i have it right now:

function filter_email_text_for_post_link( $post ) {

// retrieve the 'proposal_email' post_meta (array)
$post_meta = get_post_meta( $post->ID, 'proposal_email', TRUE );
// retrieve email body 'proposal_email_text' from array
$email_content = $post_meta['proposal_email_text'];

// bail if email has no content
if( $email_content == '' ){ return; }

// patterns to look for in email body
$link_pattern = '%%PROPOSAL_LINK%%';
$url_pattern  = '%%PROPOSAL_LINK_URL%%';

// returns for each pattern
$proposal_link = '<a href="' . get_permalink( $post_id ) . '">here</a>';
$porposal_link_url = get_permalink( $post_id );

// match and replace with the above patterns
$email_content = str_replace( $link_pattern, $proposal_link, $email_content );
$email_content = str_replace( $url_pattern, $proposal_link_url, $email_content );

// update the post_meta
$post_meta['proposal_email_text'] = $email_content;
update_post_meta( $post->ID, 'proposal_email', $post_meta );

}

add_action( 'save_post', 'filter_email_text_for_post_link' );

for some reason, this just isn't working; at all, no errors, no nothing! Initially i tried invoking this function (slightly edited) in the function which saves the data on save_post but that wasn't working either.

Any suggestions?

Thanks in advance.

3 Answers 3

3

preg_replace expects it's regex to be surrounded by a character. Usually that's a slash, like this:

'/.*/'

When you do this:

preg_replace('%%PROPOSAL_LINK_URL%%', $some_text, $replacement);

preg_replace thinks the first two % are your surrounding characters, and fails because of an unrecognized modifier. This is easy to test:

$ php -a
Interactive shell

php > echo preg_replace('%%PROPOSAL_LINK_URL%%', '%%PROPOSAL_LINK_URL%%', 'here'), PHP_EOL;
PHP Warning:  preg_replace(): Unknown modifier 'P' in php shell code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
PHP   2. preg_replace() php shell code:1

Warning: preg_replace(): Unknown modifier 'P' in php shell code on line 1

Call Stack:
   28.9460     235264   1. {main}() php shell code:0
   28.9460     236016   2. preg_replace() php shell code:1


php > 

You have two options:

Change your patterns to something like this: /%%PROPOSAL_LINK_URL%%/ and /%%PROPOSAL_LINK%%/

$ php -a
Interactive shell

php > echo preg_replace('/%%PROPOSAL_LINK_URL%%/', '%%PROPOSAL_LINK_URL%%', 'here'), PHP_EOL;
here

Forget all about preg_replace because you don't need it. Use str_replace or str_ireplace instead.

<?php
str_replace('%%PROPOSAL_LINK_URL%%', $proposal_link_url, $email_content);
str_ireplace('%%PROPOSAL_LINK%%', $proposal_link, $email_content);

Be aware that str_replace and it's brethren are not safe for use on strings that contain multi-byte characters (eg. UTF-8) by default. You can change this.

NOTE: you've used $link_pattern twice in your code examples. I think you mean the second one to be $url_pattern.

EDIT: it appears there's not a mb_* replacement for str_replace or str_ireplace this comment on php.net sheds some light on the issue. str_replace should work on multibyte strings, providing the encoding of the needle and haystack are the same.

7
  • thanks for pointing out the error in the code, also i wasn't aware that str_replace wasn't safe tu use with UTF-8 so much appreciated. Sep 23, 2013 at 14:01
  • Which is the overloading function for str_replace?
    – gmazzap
    Sep 23, 2013 at 14:18
  • oooo, good catch. I don't think there is one. Sep 23, 2013 at 14:26
  • unofficialy mb_str_replace apparently but according to some comments on [link]php.net/manual/en/ref.mbstring.php str_replace works just fine in a multi-byte strings; there are several functions on that site if anyone is having any problems though. I haven't tested any of them though. Sep 23, 2013 at 14:28
  • @Ronnieinspain mb_str_replace does not exists as mbstring function. And str_replace works perfectly with utf-8 strings see here.
    – gmazzap
    Sep 24, 2013 at 2:49
1

Your problem is a not-escaped regex. However you don't need preg_replace, just a str_replace

$email_content = str_replace( $link_pattern, $proposal_link, $email_content );
$email_content = str_replace( $link_pattern, $porposal_link_url, $email_content );

FYI, the right way for regex is, in this case:

$link_pattern = preg_quote('%%PROPOSAL_LINK%%');
$email_content = preg_replace( '/' . $link_pattern . '/', $proposal_link, $email_content);
6
  • This has nothing to do with un-escaped regex. The % is not a meta character. preg_quote('%%PROPOSAL_LINK%%') === '%%PROPOSAL_LINK%%'; in other words. Sep 23, 2013 at 13:52
  • @G.M. thanks for the suggestion; i have tried both escaping the regex and as per your suggestion, using str_replace; still nothing happening however... btw is there any performance benefit in using str_replace ? Thanks Sep 23, 2013 at 13:55
  • Yes, I know. For "unescaped" I mean "without a proper regex delimiter". But "unescaped" is more clear (even for a beginner) and is only one word. I added the preg_quote because if the OP (or someone else in future) use this code with another pattern with problematic chars, will have an error. Once preg_quote do not hurt, I just added it. @chrisguitarguy
    – gmazzap
    Sep 23, 2013 at 13:57
  • @Ronnieinspain yes, str_replace is faster than preg_replace.
    – gmazzap
    Sep 23, 2013 at 13:58
  • @Ronnieinspain have you tried to var_dump($email_content) and var_dump($proposal_link)?
    – gmazzap
    Sep 23, 2013 at 14:01
0

The final, working function:

In comparison to my initial function ended up using str_replace in stead of preg_replace as the resulting code was shorter more concise and faster. Also added two arguments to the add_action call removing the need to use Global $post; furthermore removed notices in case where $post_meta['proposal_email_text'] has not been set (new post).

function filter_email_text_for_post_link( $post_id, $post ) {

// retrieve the 'proposal_email' post_meta (array)
$post_meta = get_post_meta( $post->ID, 'proposal_email', TRUE );
// retrieve email body 'proposal_email_text' from array
if( ! empty( $post_meta['proposal_email_text'] ) ){
    $email_content = $post_meta['proposal_email_text'];
} else {
    return; 
}

// bail if email has no content
if( $email_content == '' ){ return; }

// patterns to look for in email body
$link_pattern = '%%PROPOSAL_LINK%%';
$url_pattern  = '%%PROPOSAL_LINK_URL%%';

// returns for each pattern
$proposal_link = '<a href="' . get_permalink( $post_id ) . '">here</a>';
$proposal_link_url = get_permalink( $post_id );

// match and replace with the above patterns
$email_content = str_replace( $link_pattern, $proposal_link, $email_content );
$email_content = str_replace( $url_pattern, $proposal_link_url, $email_content );

// update the post_meta
$post_meta['proposal_email_text'] = $email_content;
update_post_meta( $post->ID, 'proposal_email', $post_meta );

}

add_action( 'save_post', 'filter_email_text_for_post_link', 10, 2 );
2
  • Add an explanation about what was wrong to this answer, and how you fixed it. Then accept it. Helps the next person who comes along. Sep 23, 2013 at 14:31
  • Also, you don't need a global. Tell add_action to pass two arguments and the second will be the $post object. Sep 23, 2013 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.