How to create a Wordpress shortcode-style function in PHP - php

I am trying to create a Wordpress shortcode-style feature in PHP to replace shortcodes like "[[133]]" with images. Basically, I have a MySQL table of image URLs/titles/subtitles with IDs 1-150, and I want to be able to dynamically insert them into the text of my pages with shortcodes like this:
Blabla bla bla bla bla. [[5]] Also, bla bla bla bla bla [[27]]
Hey, and bla bla bla! [[129]]
So, I just want to grab the ID as $id, and then feed it to a MySQL query like
mysql_query("SELECT title,subtitle,url FROM images WHERE id = $id")
and then replace the "[[id]]" with the img/title/subtitle. I would like to be able to do this multiple times on the same page.
I know this has to involve regex and some combination of preg_match, preg_replace, strstr, strpos, substr... but I don't know where to start and which functions I should be using to do which things. Can you recommend a strategy? I don't need the code itself—just knowing what to use for which parts would be extremely helpful.

If you want to be able to write shortcodes like this :
[[function_name_suffix parameter1 parameter2 ...]]
here is a more complete way, using preg_replace_callback and call_user_func_array to implement parameterized shortcodes.
function shortcodify($string){
return preg_replace_callback('#\[\[(.*?)\]\]#', function ($matches) {
$whitespace_explode = explode(" ", $matches[1]);
$fnName = 'shortcode_'.array_shift($whitespace_explode);
return function_exists($fnName) ? call_user_func_array($fnName,$whitespace_explode) : $matches[0];
}, $string);
}
If this function is defined :
function shortcode_name($firstname="",$lastname=""){
return "<span class='firstname'>".$firstname."</span> <span class='lastname'>".$lastname."</span>";
}
Then this call
print shortcodify("My name is [[name armel larcier]]");
Will output :
My name is <span class='firstname'>armel</span> <span class='lastname'>larcier</span>
This is just something I implemented right now based on supertrue's idea.
Any feedback is more than welcome.

With a function getimage($id) that does the MySQL query and formats the replacement text, this almost does everything you need:
$text = "Blabla [[5]] and [[111]] bla bla bla [[27]] and bla bla bla! [[129]]";
$zpreg = preg_match_all('#\[\[(\d{1,3})\]\]#', $text, $matches );
var_dump( $matches[1] );
$newtext = preg_replace('#\[\[(\d{1,3})\]\]#', getimage($matches[1][?????]), $text);
echo $newtext;
I just need to figure out what to put inside getimage() (where ????? is) that will make it put in the right image for the right [[id]].
Refer preg_match_all and preg_replace on official documentation for more details.

Various different approaches can be taken for this, depending on how you plan to display ect,
Take the sentence "Hello [34] world"
Create a simple function e.g replaceCode($string)
function replaceCode($string){
$pos = strpos($string, '['); // Find the first occurrence of the bracket
if($pos != false){
// If everything is ok take the next 2 numbers from it
// Check for a close bracket & remove ]
// call another function to replace the number with the image text
}
}
If anymore occurrences of brackets are found, recursively call the function again, passing the rest of the string to the function again.
Note: Validation may need to be done first to ensure the [ and ] are properly balanced!

My bet is PHP's strtr function...
<?php
function get_profile_image($image_url){
return "<img src='{$image_url}' height='200px' width='200px' />";
}
$trans = array(
"[[1]]" => "Vishal",
"[[2]]" => "Kumar",
"[[3]]" => "Sahu",
"[[4]]" => "Web Designer",
"[[5]]" => "Draw and Paint",
"[[6]]" => ucwords("any programming language"),
"[[7]]" => strtoupper("PHP, JAVASCRIPT and HTML"),
"[[8]]" => get_profile_image("http://php.net/images/logos/php-logo.svg"),
"[[9]]" => "http://php.net/images/logos/php-logo.svg"
);
$str = <<<HEREDOC_1
[[8]]
<pre>My name is [[1]] [[2]] [[3]].
I am a [[4]] and I love to [[5]].
I don't know [[6]] but I know [[7]] little bit.</pre>
Here is my profile image <img src='[[9]]' alt='[[1]]-[[2]]-[[3]]-[[4]]' />
HEREDOC_1;
echo strtr($str, $trans);
it's output is
[http://php.net/images/logos/php-logo.svg] My name is Vishal Kumar
Sahu. I am a Web Designer and I love to Draw and Paint. I don't know
Any Programming Language but I know PHP, JAVASCRIPT AND HTML little
bit. Here is my profile image [Vishal-Kumar-Sahu-Web Designer]
It is working fine on 5.6.

The regex, I believe, would be:
/\[\[[1-9]{1,3}\]\]/g
(for a 1-to-3 digit number inside double brackets.)

Related

PHP - Replace everything between String including content

I want to iterate over a string which looks like this.
Booo ahh [Hello] and what is [Baby] at your [Mouse]
My target is to replace every [###] with another string, which is not static, but can handle the content between the brackets.
Should be something like
function replace_string($text) {
...
//Maybe some kind of loop for all brackets
{
$content = ... //For example Hello, Baby, Mouse => ###
$replacement = "I'm a " . $content . "!";
...
}
return $replacedString;
}
I don't think it can work like in my "suggestion", but I hope I could show what I want to do and somebody can help me.
For what i understand, you want to have this string at the end:
Booo ahh [I'm a Hello!] and what is [I'm a Baby!] at your [I'm a Mouse!]
So you can use preg_replace function: http://php.net/manual/en/function.preg-replace.php
Your code will looks like:
function replace_string($text)
{
return preg_replace('/\[([^\]]+)\]+/', "[I'm a $1!]", $string);
}
so
<?php
$string = 'Booo ahh [Hello] and what is [Baby] at your [Mouse]';
echo replace_string($string);
// will display
// Booo ahh [I'm a Hello!] and what is [I'm a Baby!] at your [I'm a Mouse!]
not sure if you want to keep the brackets or not, if you don't, and want to have
Booo ahh I'm a Hello! and what is I'm a Baby! at your I'm a Mouse!
just use:
preg_replace('/\[([^\]]+)\]+/', "I'm a $1!", $string);
You can see the regex here: https://regex101.com/r/8hJQr0/1

get 2 elements by preg_match from a html file

can't understand how it works preg_match, tryed today few hours to create my function with lot of examples, even documentation and didnt help me. so need yours help please.
need te get 2 elements
first is element name menu, secound is content between tags {main}
looks like
{main item=menu} bla bla bla{/main}
An simple regex would be /\{([a-z]+)\s*item=([a-z]+)\}(.*?)\{\/\1\}/. Applied to your example, this would return the matching groups main, menu and bla bla bla.
if (preg_match('/\{([a-z]+)\s*item=([a-z]+)\}(.*?)\{\/\1\}/', $data, $m)) {
if ($m[2] == 'menu') {
// do something usefull..
$content = $m[3];
}
}
you could even use preg_match_all, to iterate over all elements, matching this pattern.

Function that can identify certain texts

Here's my problem. I'll try to keep it concise:
I have a wab page that displays the texts in the selected language like this:
<p><?php echo $langFile->data->message; ?></p>
The actual text can look like this:
Hello, %1. You have %2 orders. If you %forgot% your password click %here% !
So I have to write a function that can replace (called one time for each replacement) the %1 and %2 with certain texts, and the words between % to be replaced with a link text. The reason it's tricky is that I can have texts that look like this:
Bla bla %1, bla %yada yada %2 yada% bla bla bla.
So here, the function has to replace %yada yada %2 yada% with a linkable text and, when called again, can replace %2 with another text.
I'm kind of new with programming, so I could use some pointers since I don't know how to get where I want if even possible. Thanks a lot in advance.
Regards
$whatever = explode('%', $something);
Then run through it like any other array. If you can find a common denominator and explode it, you can usually get any puzzle of regex or if/then to work how you need. The logic practically reveals itself afterwards.
As an example, I tried to find a way to guarantee removal of ALL script tags. Honestly, no one's regex worked. Then, I found the common denominator in html that I can use. I came up with this. It will guarantee to strip all script tags. Of course, it's only this simple with script tags because they won't be nested. However, it's a great example of how to use "exploding logic" or "accordion coding" to get your mind wrapped around the problem and make it happen.
$h = explode('>', $html);
foreach($h as $k => $v){
$v = trim($v);
if(preg_match('/^(<script[.*]*)/ius', $v)){
$counter = $k;//starting key of the script stored for later
}elseif(preg_match('/([.*]*<\/script$)/ius', $v)){
$script = $k - $counter;//difference between opening and closing tag
$counter = 0;//reset counter for next script
for($i = $script; $i >= 0; $i--){//now use the keys to empty everything in between
$h[$k-$i] = '';
}
}
}
for($i = 0; $i <= count($h); $i++){
if($h[$i] != ''){
$ht[$i] = $h[$i];//clean out the blanks so when we implode it works right.
}
}
$html = implode('> ', $ht);//all scripts stripped.GUARANTEED
I believe you can use this same idea with what you are trying to do. Though your internal statements will vary, but you will begin to see how it can flow more easily and actually show progress on what you are trying to do.
Try this: preg_replace http://php.net/manual/es/function.preg-replace.php
May be %[1-9] for the %1, %2, %3 and %[A-Za-z ]+% for the other.
There is something important... You should change the % to any other caracter for one of the cases... that make easier the search, because...
This case is easy: Hello, %1. You have %2 orders. If you %forgot% your password click %here% !
This is not: Bla bla %1, bla %yada yada %2 yada% bla bla bla.
But this, for example is easier: Bla bla #1, bla %yada yada #2 yada% bla bla bla.
Rather than using % you can use string variables in the text (unless you're writing some sort of a dynamic thing that will allow people to add their own vars like a CMS). You would make the variables come out of a database or something like that for the different languages. Example:
$name = 'Bob';
$salutation = "Hello, $name.";
$order_count = '2';
if ($order_count == '1'){
$ordertext = "You have $order_count order.";
} else{
$ordertext = "You have $order_count orders.";
}
$forgot = 'forgot';
$link = 'http://www.domain.com/reset/password';
$forgotphrase = "If you $forgot your password click <a href='$link'>here</a>!";
$message = $salutation.$ordertext.$forgotphrase;
Output
Hello, Bob. You have 2 orders. If you forgot your password click here!
Update
To do this on a larger scale you could have a database table called 'phrasing'.
id,salutation,ordertext_plur,ordertext_sing,forgot,link,forgotphrase,language,updated
So in MySQL might look like this:
1,
'Hello, $name.',
'You have $order_count orders.',
'You have $order_count order.',
'forgot',
'http://www.domain.com/reset/password/en',
'If you $forgot your password click <a href='$link'>here</a>!',
'EN',
'2013-04-23 00:00:00'
Your SQL statement would look like:
select * from phrasing where language='EN';
Then you would assign the appropriate vars based on the output. You would have to give more thought to how you would implement this and how large the database should be.
Other thoughts You might consider using something like the Google Translate Gadget on your pages to translate the HTML code, instead of hard-coding translations into the database. Their database of translations is updated daily. Some of my large international clients use it instead of paying the money to translate into every language. Also it makes it easier to make changes to the code in one language without having to worry about missing it in others.

Php preg_replace_callback no work me

I try replace characters from string and put others , for this use preg_replace_callback function , the problem is this function change order of original text and show differents results
For example if the string it´s :
Hello everybody [1-2-3] this it´s one test [4-5-6-7-8] --- > ORIGINAL TEXT
The script search the [ ] and separate this content with [ ] from the other text , but show me as i put here :
1-2-3 4-5-6-7-8 Hello Everybody this it´s one test --- > BAD RESULT
When the right order it´s the first without [ ]
Hello everybody 1-2-3 this it´s one test 4-5-6-7-8
The script i create :
<?php
$text = " This is a test [gal~ruta~100~100] This is other test [gal~ruta2~100~100]";
function gal($matches)
{
global $text;
$exp=explode("~",$matches[1]);
$end=str_replace($matches[1],$a,$text);
if ($exp[0]=="gal")
{
$a="".$exp[1]."".$exp[2]."".$exp[3]."";
echo $a;
}
}
echo preg_replace_callback(
"/\[(.*?)\]/",
"gal",
$text);
?>
Thank´s everybody for the help
You need to return something from your callback, which will be substituted in the original string. You most certainly don't want to echo, which will send the values straight to the output, in order of execution.
However, it sounds like you don't even need a callback function to remove the brackets around your numbers.
$str = preg_replace("/\[(.*?)\]/", "$1", $str);
CodePad.

Need to extract special tags and replace them based upon their contents using regular expression

I'm working on a simple templating system. Basically I'm setting it up such that a user would enter text populated with special tags of the form: <== variableName ==>
When the system would display the text it would search for all tags of the form mentioned and replace the variableName with its corresponding value from a database result.
I think this would require a regular expression but I'm really messed up in REGEX here. I'm using php btw.
Thanks for the help guys.
A rather quick and dirty hack here:
<?php
$teststring = "Hello <== tag ==>";
$values = array();
$values['tag'] = "world";
function replaceTag($name)
{
global $values;
return $values[$name];
}
echo preg_replace('/<== ([a-z]*) ==>/e','replaceTag(\'$1\')',$teststring);
Output:
Hello world
Simply place your 'variables' in the variable array and they will be replaced.
The e modifier to the regular expression tells it to eval the replacement, the [a-z] lets you name the "variables" using the characters a-z (you could use [a-z0-9] if you wanted to include numbers). Other than that its pretty much standard PHP.
Very useful - Pointed me to what I was looking for...
Replacing tags in a template e.g.
<<page_title>>, <<meta_description>>
with corresponding request variables e,g,
$_REQUEST['page_title'], $_REQUEST['meta_description'],
using a modified version of the code posted:
$html_output=preg_replace('/<<(\w+)>>/e', '$_REQUEST[\'$1\']', $template);
Easy to change this to replace template tags with values from a DB etc...
If you are doing a simple replace, then you don't need to use a regexp. You can just use str_replace() which is quicker.
(I'm assuming your '<== ' and ' ==>' are delimiting your template var and are replaced with your value?)
$subject = str_replace('<== '.$varName.' ==>', $varValue, $subject);
And to cycle through all your template vars...
$tplVars = array();
$tplVars['ONE'] = 'This is One';
$tplVars['TWO'] = 'This is Two';
// etc.
// $subject is your original document
foreach ($tplVars as $varName => $varValue) {
$subject = str_replace('<== '.$varName.' ==>', $varValue, $subject);
}

Categories