Pass variable from loop to function - php

I've been working with Php for less than 2 months (this is also my first question so please tell me if I'm missing something) and it has been going smooth right up till today. I'm working on a form plugin for Wordpress and currently implementing the code to make the forms saved in the database to connect with a shortcode which includes the ID of the form in the database. The 1st form has an ID of 1 and the shortcode is IForm_1. Pretty simple.
The problem occurs when looping thru all the forms and not being able to pass the $ID value from the loop to the IForm function.
$ID= 0;
$FormID= 0;
settype($ID, "integer");
for ($x = 1; $x <= 300; $x++) {
global $ID;
$ID++;
$ShortCode = "IForm_";
$ShortCode .= $ID;
$FormID = $ID;
add_shortcode( $ShortCode, 'IForm_Array' );
$ShortCode ='';
}
here is the loop which is very simple, when the $ShortCode lines up with the shortcode used on the site it works and the IForm get used as it should.
function IForm(){
global $ID;
//testing_decode();
// Gets the value of baseTest from getDB and puts it in test.
$DBForm = getDB($ID);
$Form = $DBForm;
$Form .= "Works but not really";
return $Form;
}
Here is the function.
Problem is that $ID is always 300 in the function which is the end of the loop. IForm is executed when the $ID in the loop lines up with the shortcode ID on the site/post which tells me the $ID value is indeed correct for some part of the loop. When the ID is indeed correct I would like to pass it to the IForm function to use it to find the right form in the database(MySQL).
Now my question is how would I pass (if that can even be done) the $ID value on the 3rd row of the loop to the 5th row of function. Alternatively would be to force break the loop when it lines up and use the last $ID value to be passed to IForm.

WordPress makes this a little more complicated than it needs to be, because you can't pass additional parameters to a shortcode (afaik).
Before we start, let's understand the 300. The loop in which you add the shortcodes gets executed during an early stage of the page load. The actual call to your shortcode function at a later stage. At that time the global $ID variable will have its final value (300 in your case)
Here are two ways to solve this:
First, you can use closures, and inherit $ID from the parent scope:
for ($x = 1; $x <= 300; $x++) {
$ID++;
$ShortCode = "IForm_";
$ShortCode .= $ID;
$FormID = $ID;
add_shortcode( $ShortCode, function () use ($ID) {
$DBForm = getDB($ID);
$Form = $DBForm;
$Form .= "Works but not really";
return $Form;
} );
$ShortCode ='';
}
You can read more about it in the manual. It also explains the difference between use and global variables.
Second, you can use shortcode attributes. You would not use [Form_1] anymore, but [Form id=1]. Then you can access the id within the array that Wordpress automatically passes to your function.
function IForm($attr){
$ID = intval($attr['id']); // A little sanitation, because $attr could come from a user with low privileges
$DBForm = getDB($ID);
$Form = $DBForm;
$Form .= "Works but not really";
return $Form;
}
A little documentation about this is available here.

Lets see what you did there
$ID= 0;
// Define a variable called ID
for ($x = 1; $x <= 300; $x++) {
global $ID;
// get access to global variable id
$ID++;
// increment local or global counter, undefined behaviour
instead i recommend doing
global $ID;
for ($x = 1; $x <= 300; $x++) {
$ID++;
// Do what you think you have to do
do not pass variables over global variables into functions, instead use parameter
function IForm($id){
//testing_decode();
$DBForm = getDB($id);
$Form = $DBForm;
$Form .= "Works very good";
return $Form;
}
and call the function like
IForm(42); //or
IForm($ID);

Related

How to generate a random code for each session using php for Wordpress?

I am using Contact form 7 in Wordpress , where I want to add a field of uneditable random code . I am using the following code and using the Dynamic hidden field to display it. But is there any way that I can show this code on any page (where I want) after submitting this form? e.g, Your submitted code was : 32372377
function rzh_cf7_GenNomor() {
$panjang = 10; // Length number generated
$karakter = "0123456789"; // random character
for ($p = 0; $p < $panjang; $p++) {
$string .= $karakter[mt_rand(0,strlen($karakter)-1)];
}
return $string;
}
add_shortcode('RZH_CF7_GEN_NOMOR', 'rzh_cf7_GenNomor');
You can add data to the global $_SESSION variable that will be accessible at any point within the application during a user session by accessing the $_SESSION variable. The variable is an array; below is an example of adding data to the session array.
$foo = add_shortcode('RZH_CF7_GEN_NOMOR', 'rzh_cf7_GenNomor');
$_SESSION[‘foo’] = $foo;
You can call the following function in your custom shortcode in function.php
function generateRandomString($length = 10) {
return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,$length);
}

Call variable correct and display PHP generated HTML in the_content()

I’m creating a plugin called woomps. In the main php file i do a calculation when template redirect.
add_action('template_redirect','woomps_loop');
This calculates x: (it’s actually a big calculation).
function woomps_loop() {
$x = 10;
Return $x
}
I want to show this variable based on a shortcode. Therefore, in my main php file I include the frontend.php through this code.
function woomps_scripts() {
include 'frontend.php';
}
add_action('wp_enqueue_scripts','woomps_scripts');
Where the frontend.php has this code
function woomps_subscription_slider (){
//How do I call the variable from woomps_loop() without running all the code again.
echo "<div>\n";
echo "<p>\n";
echo $x;
echo "</p>\n";
echo "</div>\n";
}
add_shortcode("woomps-subscription-slider", "woomps_subscription_slider");
The shortcode is added to one of my pages so it displays, but……
How do I call the $x variable form woomps_loop() without running the code again?
This <div> will come before all other content generated in the_content(). Why is that?
global $x; //Had to define it global before setting it, i dident understand this before #cameronjonesweb exmample.
$x = $total_qty;
Then reference it like this:
function woomps_subscription_slider ($x){
global $x_subs;
$content = <<<EOD
<div>
<p>
{$x_subs}
</p>
</div>
EOD;
return $content;
} //end woomps_subscription_slider
It worked. Try this EOD to return multiple lines of HTML, and it does get placed inside the_content() loop
Okay. Thank you!
1) Store it as a global variable. So change your woomps_loop function to
global $x;
function woomps_loop() {
global $x;
$x = 10;
return $x
}
(PS you probably won't need to return $x here now)
Then also define $x in your shortcode function
function woomps_subscription_slider (){
global $x;
echo "<div>\n";
//... rest of it carries on
2) Because you're echoing. Return the value instead.

How do I share same variable between independent functions

How do I share same variable between independent functions? I don't want to use globals and at the moment, I'm not using OO. This example only works within nested functions:
$example = function() use ($id){
echo 'id is: ' . $id;
};
Is there a way to access (read: to call) that nested function from a different function? I could then return $id.
Main issue: I'm retrieving an ID from a database and I want the moderator to be able to edit material based on the ID that is being retrieved from the database.
As mentioned in my comment , I'm not 100% what exactly you mean by independent and nested function but here is PHP's manual on (anonymous function)[http://php.net/manual/en/functions.anonymous.php].
Anyway I have put a sample together assuming you are really meaning nested functions
<?php
function wrapperOne($id) {
$newId = function($id) {
return $id * 2;
};
return $newId($id);
}
function wrapperTwo($id) {
$doSomething = function() use(&$id) {
$id *= 3;
};
$doSomething();
return $id;
}
echo wrapperOne(2); // 4;
echo PHP_EOL;
echo wrapperTwo(2); // 6;
You can use passing by reference read this
function changeMyID(&$id)
{
$id = 1;
}
function printMyID($id)
{
echo $id;
}
$id = 2;
changeMyID($id);
printMyID($id); // this will output 1;

Return string and run it as code

I'm trying to create an Autoloader class, so that I'll be able to load all modules automatically. But the problem is, I want to set a global from configuration file, and later, just call all of them by using:
Autoloader::GetGlobals();
So far, I have these 3 files:
Configuration.php
<?php
global $Configuration;
$Configuration['Globals'] = "Core Database Templates Directory Debugger";
?>
Autoloader.Class.php
<?php
require_once('Configuration.php');
private static $Globals = "";
private static $MakeGlobal = "global ";
public static function GetGlobals()
{
$ParsedGlobals = "";
$Globals2String = explode(" ", Autoloader::$Globals);
foreach($Globals2String as $Global)
$Globals[] = "$".$Global;
$DefinedGlobals = count($Globals);
for ($i = 0; $i < $DefinedGlobals; $i++)
{
$LastElement = $DefinedGlobals - 1;
if($i != $LastElement)
$ParsedGlobals .= $Globals[$i].", ";
else
$ParsedGlobals .= $Globals[$i].";";
}
return Autoloader::$MakeGlobal.$ParsedGlobals;
}
?>
I'm getting the right output:
global Core, Database, Templates, Directory, Debugger;
The next thing is that I want to interpret this as PHP code and not as a string, and I don't want to use eval() (because I've read many articles that says that this is the last function to be used).
So the question is, is it possible to run this string from return as PHP code by simply calling it as Autoloader::GetGlobals();?
It's almost as bad as using eval(), but there's variable variables, if you choose to go down this path of madness and chaos:
function foo($arg) {
global $$arg; // note the $$
echo "$arg / $$arg";
}
$a = 'bar';
foo('a');
output:
a / bar

Simple template var replacement, but with a twist

So I'm setting up a system that has a lot of emails, and variable replacement within it, so I'm writing a class to manage some variable replacement for templates stored in the database.
Here's a brief example:
// template is stored in db, so that's how this would get loaded in
$template = "Hello, %customer_name%, thank you for contacting %website_name%";
// The array of replacements is built manually and passed to the class
// with actual values being called from db
$replacements = array('%customer_name%'=>'Bob', '%website_name%'=>'Acme');
$rendered = str_replace(array_keys($replacements), $replacements, $template);
Now, that works well and good for single var replacements, basic stuff. However, there are some places where there should be a for loop, and I'm lost how to implement it.
The idea is there'd be a template like this:
"hello, %customer_name%, thank you for
requesting information on {products}"
Where, {products} would be an array passed to the template, which the is looped over for products requested, with a format like:
Our product %product_name% has a cost
of %product_price%. Learn more at
%product_url%.
So an example rendered version of this would be:
"hello, bob, thank you for requesting
information on:
Our product WidgetA has a cost of $1.
Learn more at example/A
Our product WidgetB has a cost of $2.
Learn more at example/B
Our product WidgetC has a cost of $3.
Learn more at example/C.
What's the best way to accomplish this?
Well, I really dont see the point in a template engine that uses repalcements/regex
PHP Is already a template engine, when you write <?php echo $var?> its just like doing <{$var}> or {$var}
Think of it this way, PHP Already translates <?php echo '<b>hello</b>'?> into <b>hello</b> by its engine, so why make it do everything 2 times over.
The way i would implement a template engine is like so
Firstly create a template class
class Template
{
var $vars = array();
function __set($key,$val)
{
$this->vars[$key] = $val;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : false;
}
function output($tpl = false)
{
if($tpl === false)
{
die('No template file selected in Template::output(...)');
}
if(!file_exists(($dir = 'templates/' . $tpl . '.php')))
{
die(sprintf('Tpl file does not exists (%s)',$dir));
}
new TemplateLoader($dir,$this->vars);
return true;
}
}
This is what you use in your login such as index.php, you will set data just like an stdClass just google it if your unsure. and when you run the output command it sends the data and tpl to the next class below.
And then create a standalone class to compile the tpl file within.
class TemplateLoader
{
private $vars = array();
private $_vars = array(); //hold vars set within the tpl file
function __construct($file,$variables)
{
$this->vars = $variables;
//Start the capture;
ob_start();
include $file;
$contents = ob_get_contents();
ob_end_clean(); //Clean it
//Return here if you wish
echo $contents;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : (isset($this->_vars[$key]) ? $this->_vars[$key] : false) : false;
}
function __set($key,$val)
{
$this->_vars[$key] = $val;
return true;
}
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
}
The reason we keep this seperate is so it has its own space to run in, you just load your tpl file as an include in your constructor so it only can be loaded once, then when the file is included it has access to all the data and methods within TemplateLoader.
Index.php
<?php
require_once 'includes/Template.php';
require_once 'includes/TemplateLoader.php';
$Template = new Template();
$Template->foo = 'somestring';
$Template->bar = array('some' => 'array');
$Template->zed = new stdClass(); // Showing Objects
$Template->output('index'); // loads templates/index.php
?>
Now here we dont really want to mix html with this page because by seperating the php and the view / templates you making sure all your php has completed because when you send html or use html it stops certain aspects of your script from running.
templates/index.php
header
<h1><?php $this->foo;?></h1>
<ul>
<?php foreach($this->bar as $this->_foo):?>
<li><?php echo $this->_foo; ?></li>
<?php endforeach; ?>
</ul>
<p>Testing Objects</p>
<?php $this->sidebar = $this->foo->show_sidebar ? $this->foo->show_sidebar : false;?>
<?php if($this->sidebar):?>
Showing my sidebar.
<?php endif;?>
footer
Now here we can see that were mixing html with php but this is ok because in ehre you should only use basic stuff such as Foreach,For etc. and Variables.
NOTE: IN the TemplateLoader Class you can add a function like..
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
This will allow you to increase your actions in your templates so bold,italic,atuoloop,css_secure,stripslashs..
You still have all the normal tools such as stripslashes/htmlentites etc.
Heres a small example of the bold.
$this->bold('foo'); //Returns <strong>somestring</string>
You can add lots of tools into the TempalteLoader class such as inc() to load other tpl files, you can develop a helper system so you can go $this->helpers->jquery->googleSource
If you have any more questions feel free to ask me.
----------
An example of storing in your database.
<?php
if(false != ($data = mysql_query('SELECT * FROM tpl_catch where item_name = \'index\' AND item_save_time > '.time() - 3600 .' LIMIT 1 ORDER BY item_save_time DESC')))
{
if(myslq_num_rows($data) > 0)
{
$row = mysql_fetch_assc($data);
die($row[0]['item_content']);
}else
{
//Compile it with the sample code in first section (index.php)
//Followed by inserting it into the database
then print out the content.
}
}
?>
If you wish to store your tpl files including PHP then that's not a problem, within Template where you passing in the tpl file name just search db instead of the filesystem
$products = array('...');
function parse_products($matches)
{
global $products;
$str = '';
foreach($products as $product) {
$str .= str_replace('%product_name%', $product, $matches[1]); // $matches[1] is whatever is between {products} and {/products}
}
return $str;
}
$str = preg_replace_callback('#\{products}(.*)\{/products}#s', 'parse_products', $str);
The idea is to find string between {products} and {products}, pass it to some function, do whatever you need to do with it, iterating over $products array.
Whatever the function returns replaces whole "{products}[anything here]{/products}".
The input string would look like that:
Requested products: {products}%product_name%{/products}

Categories