Wordpress get_option() with index key from string - php

--Edited--
I've made a admin form which adds some custom functions to my theme. Loading the settings page I first get the current settings from the database. For this I use get_option().
The setting field is called product_settings
To get all values from this setting you can call it with: $option = get_option('product_settings');
The result of this is equivalent to this:
$option = [
'product_01' => [
'style' => [
'color' => [
'primary' => '#ffffff'
]
]
]
];
Now, to get the value of index 'primary' I would call it like this:
From DB:
$optionColorPrimary = get_option('product_settings')['product_01']['style']['color']['primary'];
From array:
$optionColorPrimary = $option['product_01']['style']['color']['primary'];
Now, this work all fine and that. But now comes the tricky part. The index location is passed in a string value like this:
$get_option_srt = 'product_settings[product_01][style][color][primary]';
First part is the db field. And the part after it, separated by square brackets are the nested indexes.
My Question
How do I get to the nested value of this array based on the indexes from the string?
This is my attempt so far:
$get_option_srt = 'product_settings[product_01][style][color][primary]';
// split in two, to separate the field name from the indexes.
$get_option_srt = preg_split('/(\[.*\])/', $get_option_srt, 2, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
// yes, this does not work...
// The part after get_option() is wrong. Here are the nested index locations needed
$option = get_option( $get_option_srt[0] )[ $get_option_srt[1] ];
Any help is welcome.

I would recommend not attempting to get it directly off the get_option() result, but rather get the value, then parse the path.
You can write your own function that accomplishes what you want. Something like so:
NOTE: This has many "Defensive" measures in place, so that if you ask for a path that doesn't exist, or use a malformed path, this will not throw PHP notices / errors:
function get_option_by_path( $path ) {
// get all the "keys" from within the square braces
preg_match_all( '/\[(.+?)\]/', $path, $matches );
// get the initial "key" (eg, 'product_settings')
$key = explode( '[', $path );
// ensure base key is set, in case there were no square braces
$key = ( ! empty( $key[0] ) ) ? $key[0] : $key;
// load the option value from the DB
$option = get_option( $key );
if ( ! $option || ! is_array( $option ) ) {
return FALSE;
}
// if the passed-in path didn't have any square-brace keys, return the option
if ( empty( $matches[1] ) ) {
return $option;
}
// loop over all the keys in the square braces
foreach ( $matches[1] AS $key ) {
// if $option is an array (still), and has the path, set it as the new $option value
if ( is_array( $option ) && array_key_exists( $key, $option ) ) {
$option = $option[ $key ];
} else {
// otherwise, can't parse properly, exit the loop
break;
}
}
// return the final value for the $option value
return $option;
}
Usage:
$get_option_srt = 'product_settings[product_01][style][color][primary]';
$value = get_option_by_path( $get_option_srt );

You could do this:
$value = 'product_settings[product_01][style][color][primary]';
// The below should result in: 'product_settings[product_01[style[color[primary'
$key_string = str_replace(']', '', $value);
//Create an array for all the values, using '[' as the delimiter
$key_array = explode('[', $key_string);
/* Remove first value (the option name), and save the
value (which is 'product_settings' in this case) */
$option_name = array_shift($key_array);
// Get the option value (an array) from the db:
$option_settings = get_option($option_name);
// Set $option_setting to be the entire returned array:
$option_setting = $option_settings;
/*
Iterate through your key array for as many keys as you have,
changing $option_setting to be more refined on each iteration
until you get the value you need:
*/
for ($i = 0; $i < count($key_array); $i++) {
$option_setting = $option_setting[$key_array[$i]];
}
$option setting should now contain the value you need.

Related

How do I match the value of an array to a key of another array in PHP?

I have 2 arrays, one of which is built dynamically and one which I use as a map.
The map array:
$social_links_map = [
'twitter' => 'twitter-icon',
'facebook' => 'facebook-icon'
];
And my dynamic array, which is just a simple list of social links:
$dynamic_social_links = [ 'twitter.com/me', 'facebook.com/me' ];
$social_links = explode( ',', $dynamic_social_links );
The $dynamic_social_links is an user input, as such, their input can be wrongly typed.
And I need to check if within my $social_links exists any of the $social_links_map keys and return the $social_links_map item accordingly:
if( !empty( $social_links ) ) {
foreach( $social_links_map as $handle => $icon ) {
foreach( $social_links as $social_link ) {
if( strpos( $social_link, $handle ) ) {
echo $handle;
}
}
}
}
This doesn't allow for "duplicate removal", nor does it look very pretty. Any ideas?
use
array_unique
to remove "duplicated data".
Try
$social_links = array_unique(explode( ',', $dynamic_social_links ));
Firstly, is it possible that you can allow the user to select from a list of your $social_links_map?
If not then the approach you are using is likely the simplest most readable way of doing this as there is no sure fire way to be able to match potentially random user input with a predefined array of options.
A couple of things to note:
As mentioned by le Mandarin, you can use array_unique to get rid of duplicates.
The other is that strpos will return 0 (which is falsey) if the search string (needle) is found at the very start of the context variable (haystack).
eg:
strpos('twitter.link/stuff', 'twitter');
will return 0 which is false Causing your if statement to fail.
instead try something like
if (false !== strpos('twitter.link/stuff', 'twitter')) {
Take note of the extra = in !==. This is necessary because you are saying "If the result is not exactly the boolean false.

Recursive function does not return array [duplicate]

This question already has answers here:
How to use return inside a recursive function in PHP
(4 answers)
Closed 9 months ago.
I have written the function below to return parent id's of all categories in Worpress by category id. Everything works fine except it does not return the array... Any suggestions would be great! :-)
$current_category = (int) $_GET['current_category'];
$cat_ids = array($current_category);
function getParentCatIds($current_category,$cat_ids){
$child = get_category($current_category);
$parent_id = $child->parent;
if($parent_id !== 0){
array_push($cat_ids, $parent_id);
getParentCatIds($parent_id,$cat_ids);
}else{
var_dump($cat_ids); // <--- this returns the right array
return $cat_ids; // <--- this returns NULL
}
}
if($current_category){
$cat_ids = getParentCatIds($current_category,$cat_ids);
var_dump($cat_ids); // <--- this returns NULL
}
When you call getParentCatIds() (line 9), you didn't do anything with the return of the function. You should assign it or return it.
You should always sanitize input. A good starting point is filter_var(). Using the right flags for validation and sanitization and makes your input save(r). Keep in mind that FILTER_VALIDATE_* only tells you if something is valid, while FILTER_SANITIZE_* actually cleans your data from unwanted and potentially malicious data.
$currentCat = intval( $_GET['current_category'] );
$currentCat = filter_var( $currentCat, FILTER_SANITIZE_NUMBER_INT );
if ( empty( $currentCat ) ) {
// Abort – no valid data
return;
}
Then you can build an array, containing your original Category parent ID. This you can pass to array_walk(), with a callback as second parameter. The callback itself has assigned a collecting/ final array that is passed as reference and serves as target for your results. Now you can loop recursively over an indefineatly nested WordPress category hierarchy.
// Base array
$parents = [];
$callback = function( $index, $id ) use ( &$parent ) {
0 !== get_category( $id )->parent and $parents[] = $id;
};
array_walk( [ get_category( $currentCat )->parent ], $callback );
1) You should have asked at wordpress.stackexchange.com
2) I think solution is: on line 9 , instead of
getParentCatIds($parent_id,$cat_ids);
you should have
return getParentCatIds($parent_id,$cat_ids);

How to streamline filtering in Mongo database

I am attempting to filter a report by using two parameters (name and id) in a Mongo DB. The way I have it set up now is this:
// if both params are empty
if ((empty($filterParams['name'])) && (empty($filterParams['id']))) {
$views = $mongoDb->selectCollection('views')->find([], []);
}
// if one of the two params are empty
if ((!empty($filterParams['name'])) || (!empty($filterParams['id']))) {
// name is empty
if ((empty($filterParams['name']))) {
$idQuery = array('id' => (int)$filterParams['id']);
$views = $mongoDb->selectCollection('views')->find($idQuery, []);
}
// id is empty
if ((empty($filteredParams['id']))) {
$nameQuery = array('name' => $filterParams['name']);
$views = $mongoDb->selectCollection('views')->find($nameQuery, []);
}
// neither are empty
if ((!empty($filterParams['name'])) && (!empty($filterParams['id']))) {
$fullQuery = array('id' => (int)$filterParams['id'], 'name' => $filteredParams['name']);
$views = $mongoDb->selectCollection('views')->find($fullQuery, []);
}
}
I was wondering if there was a way to streamline this so that the insertion can be done one time without the multiple if statements.
You are of course overengineering a very simple problem. All you really need to do here is take your "filterParams" ( which is likely from a request source ) and convert a possible "string" value for "id" into the the "numeric" format your database seems to be expecting ( going by the code written here ).
// $filterParams = array() // or it might be blank
$filterParams = array( "id" => "1", "something" => "else" );
$query = array();
foreach( $filterParams as $key => $value ) {
if ( $key == "id" )
$query[$key] = intval($value);
$query[$key] = $filterParams[$key];
}
$views = $mongoDb->selectCollection('views')->find($query);
So just start with an empty object and simply add in or tranform the keys are required for the query. If there are no keys at all, then this is an "empty" query object as MongoDB expects, with one key or both, then the same thing would also be passed through. All you really "need" here is to cast a "string" into the expected type for a given field.
In fact, especially since "filterParams" seems to be void of other data you could just alter the values in place rather than define another structure.
// $filterParams = array() // or it might be blank
$filterParams = array( "id" => "1", "something" => "else" );
$query = array();
foreach( $filterParams as $key => $value ) {
if ( $key == "id" )
$filterParams[$key] = intval($value);
}
$views = $mongoDb->selectCollection('views')->find($filterParams);
With most dynamic languages, MongoDB queries are really just data structures in the same format as what the language natively uses to express such things. So the basic principles apply to data structure manipulation anywhere.
Same JavaScript thing for example:
//var filterParams = {};
var filterParams = {
id: "1",
something: "here"
};
Object.keys(filterParams).forEach(function(key) {
if (key == "id" )
filterParams[key] = parseInt(filterParams[key]);
});
db.collection.find(filterParams);
Also "id" is typically an identifier used for a "unique" value to an object, just as _id is always used by MongoDB. So consider that when this key is present, then all other possible query arguments become redundant, unless you "really" want to check that the correct identifier was presented with the other correct properties of the object.

Having the variable names in func_get_args()

As this function can take unknown numbers of parameters:
function BulkParam(){
return func_get_args();
}
A print_r will print only the values, but how i can retrieve the variable names as well as the array key? For example:
$d1 = "test data";
$d2 = "test data";
$d3 = "test data";
print_r(BulkParam($d1, $d2, $d3));
It will print this:
Array
(
[0] => test data
[1] => test data
[2] => test data
)
But i want to have the variables name as the index name or key name of all arrays. Then the array would look like this:
Array
(
[d1] => test data
[d2] => test data
[d3] => test data
)
I'm sure the PHP elite will have so many problems with this solution but it does work (I'm using PHP 5.6) and honestly I don't care since I've done hacks far worst than this for prototyping in many of my Java projects.
function args_with_keys( array $args, $class = null, $method = null, $includeOptional = false )
{
if ( is_null( $class ) || is_null( $method ) )
{
$trace = debug_backtrace()[1];
$class = $trace['class'];
$method = $trace['function'];
}
$reflection = new \ReflectionMethod( $class, $method );
if ( count( $args ) < $reflection->getNumberOfRequiredParameters() )
throw new \RuntimeException( "Something went wrong! We had less than the required number of parameters." );
foreach ( $reflection->getParameters() as $param )
{
if ( isset( $args[$param->getPosition()] ) )
{
$args[$param->getName()] = $args[$param->getPosition()];
unset( $args[$param->getPosition()] );
}
else if ( $includeOptional && $param->isOptional() )
{
$args[$param->getName()] = $param->getDefaultValue();
}
}
return $args;
}
Using the PHP Reflections API, we get all the method parameters and align them with their numeric indexes. (There might be a better way to do that.)
To use simply type:
print_r( args_with_keys( func_get_args() ) );
I also added the ability to optionally return the method's optional parameters and values. I'm sure this solution is far from perfect, so you're mileage may vary. Do keep in mind that while I did make it so providing the class and method was optional, I do highly suggest that you specify them if you're going anywhere near a production environment. And you should try to avoid using this in anything other than a prototype setup to begin with.
Specify the class and method with:
print_r( args_with_keys( func_get_args(), __CLASS__, __FUNCTION__ ) );
You can not. Variable names are not passed into functions. Variables are placeholders local to a specific algorithm, they are not data and they do not make sense in another scope and are not passed around. Pass an explicitly named associative array if you need key-value pairs:
bulkParam(['d1' => $d1, 'd2' => $d2, ...]);
A shortcut for this is:
bulkParam(compact('d1', 'd2'));
Then use an array:
function bulkParam(array $params) {
foreach ($params as $key => $value) ...
}
As Mark mentions in the comments, sometimes you don't even have variables in the first place:
bulkParam('foo');
bulkParam(foo(bar(baz())));
Now what?
Or eventually you'll want to refactor your code and change variable names:
// old
$d1 = 'd1';
bulkParam($d1);
// new
$userName = 'd1';
bulkParam($userName);
Your application behaviour should not change just because you rename a variable.

Save shortcode array with WordPress Options API then output in another function

Note: While this is probably a simple fix, I'm new to using arrays and am completely stumped.
I'm trying to save the data from a shortcode array via the Options API in WordPress, then call that array and use the data to create another array to hook into a plugin's function. It's a responsive slider plugin and I'm basically trying to attach a shortcode to it so I can create the slider on the backend and display it on the front end with a shortcode that looks like: [responsive_slider slider_name="imageslider"].
The implementation documentation can be found here, and here's my code:
function responsive_gallery_shortcode($atts, $content=null) {
extract(shortcode_atts( array('slider_name' => 'product_page') , $atts));
foreach ($slider_name as $value) {
update_option('_unique_slider_name', $value );
}
if(function_exists('show_flexslider_rotator'))
echo show_flexslider_rotator( $slider_name );
add_image_size( $slider_name , '550', '250', true );
}
add_shortcode('responsive_gallery', 'responsive_gallery_shortcode');
if (!function_exists('custom_set_flexslider_hg_rotators')) {
function custom_set_flexslider_hg_rotators() {
$slider_name = get_option('_unique_slider_name');
foreach ($slider_name as $value) {
$rotators = array();
$rotators[ $value ] = array( 'size' => $value );
return $rotators;
}
}
}
add_filter('flexslider_hg_rotators', 'custom_set_flexslider_hg_rotators', 9999);
I'm getting an "Invalid argument supplied for foreach()" error on both foreach functions. On the page where I have two shortcodes both errors show up twice. It seems as though $slider_name is a string instead of an array, but there's got to be a way to save it in the update_option() function so that it returns an array. I'm quite new to arrays, and I'm definitely struggling here. I've spent hours on this and have already received a little help on the WordPress side, but I'm not quite getting it.
As the shortcode attribute will arrive as a string, you need to convert it to an array first.
At the same time, as it has to be passed as a string, you'll need to use a separator so you can manage this.
And for all that, you'll need the PHP function explode.
$string = "one,two";
$array = explode( ',', $string );
var_dump( $array );
Results in:
array (size=2)
0 => string 'one' (length=3)
1 => string 'two' (length=3)
And
$string = "one";
$array = explode( ',', $string );
var_dump( $array );
Results in:
array (size=1)
0 => string 'one' (length=3)
PS: It's always worth to consult the PHP Manual and also the comments in each of its pages : http://www.php.net/manual/en/language.types.array.php
[update]
There are many issues with your original code, check the comments of this revised version:
function responsive_gallery_shortcode($atts, $content=null) {
extract(shortcode_atts( array('slider_name' => 'product_page') , $atts));
// Convert string into array
// Using comma as separator when writing the shortcode in the post
$array_slider = explode( ',', $slider_name );
// YOU DON'T NEED A `foreach` HERE
//foreach ($array_slider as $value) {
update_option('_unique_slider_name', $array_slider );
//}
// I DON'T KNOW WHAT THIS FUNCTIONS DOES
// But in any case, being $array_slider an array, maybe it should be inside a `foreach`
if(function_exists('show_flexslider_rotator'))
echo show_flexslider_rotator( $array_slider );
// THIS DOESN'T MAKE SENSE
// You're not supposed to be adding images sizes at each Shortcode call
// And you are dealing with an array
add_image_size( $slider_name , '550', '250', true );
}
add_shortcode('responsive_gallery', 'responsive_gallery_shortcode');
if (!function_exists('custom_set_flexslider_hg_rotators')) {
function custom_set_flexslider_hg_rotators() {
// The option was already saved as array, so we can work directly with it
$slider_name = get_option('_unique_slider_name');
// YOU DON'T WANT TO DECLARE THE VARIABLE AT EACH STEP OF THE LOOP
$rotators = array();
foreach ($slider_name as $value) {
$rotators[ $value ] = array( 'size' => $value );
}
// RETURN THE VALUE ONLY AFTER COMPLETING THE LOOP
return $rotators;
}
// PUT THE FILTER HOOK INSIDE if(!function_exists())
add_filter('flexslider_hg_rotators', 'custom_set_flexslider_hg_rotators', 9999);
}

Categories