Wordpress shortcode name as an Attribute - wordpress

I was wondering if possible to setup a shortcode and have the name of the shortcode also work as an attribute. How I have mine currently setup is like so
add_shortcode('tooltip', 'tooltip');
function tooltip( $atts $content = null) {
array(
'type' => '',
);
So when someone in wordpress uses the shortcode you type in
[tooltip type="fruit"]Item Name[/tooltip]
Although I was wondering is it possible to just use the name of the shortcode as a atts so I can short it a little bit and have it look like this
[tooltip="fruit"]Item Name[/tooltip]
So pretty much cut out the type attribute and use the name of the shortcode tooltip as an attribute instead.

Nope, what you're proposing isn't possible. It may be shorter but in my opinion it would be confusing so I don't see it ever being something that's made possible short of you building the functionality yourself.

You have to use first item in $atts array, ($atts[0]) when using shortcode tag as attribute.
Working example:
<?php
add_shortcode('tooltip', 'tooltip');
function tooltip(Array $atts = array(), $content = null, $tag = null) {
$args = shortcode_atts(array( 0 => null ), $atts);
$args['type'] = trim($args[0], '"=');
unset($args[0]);
extract($args);
// Your code starts here ...
$output = array(
'$type' => $type,
'$content' => $content
);
$output = '<pre>' . print_r($output, true) . '</pre>';
return $output;
}
Please replace everything after // Your code starts here ...
Executing example:
[tooltip="fruit"]Item Name[/tooltip]
will return:
<pre>Array
(
[$type] => fruit
[$content] => Item Name
)
</pre>

Related

Programmatically construct a dynamic dropdown field in Contact Form 7

I looked around here and by search engine, but unfortunately I couldn't find a solution for myself.
So, I now ask assistance with a function that I need to customize for the Contact Form 7 WordPress plugin. The function was from another question.
In a drop-down menu (select) I need two details (workshop name and date) in one option field. Both details come from the same post of a custom post type. The first detail is a post_title, the second is a custom-field from Meta-Box plugin.
The following function works in principle, but it only returns the one or the other detail. Probably the solution is within the foreach construct. But I don't know how it works.
I would be very grateful for support!
[UPDATE 2018-08-12]
After further research, I've found the solution at this post and changed the function accordingly.
The solution should look like this:
<select>
<option value="workshop name – date">workshop name – date</option>
...
</select>
This is the function:
add_filter( 'wpcf7_form_tag', 'dynamic_field_choose_workshop', 10, 2);
function dynamic_field_choose_workshop ( $tag, $unused ) {
if ( $tag['name'] != 'workshop' )
return $tag;
$args = array (
'post_type' => 'workshop',
'post_status' => 'publish',
'orderby' => 'name',
'order' => 'ASC',
'numberposts' => - 1,
);
$custom_posts = get_posts($args);
if ( ! $custom_posts )
return $tag;
foreach ( $custom_posts as $custom_post ) {
$ID = $custom_post->ID;
$tag['values'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
$tag['raw_values'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
$tag['labels'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
}
return $tag;
}
There is CF7 extension that will do this for you. Checkout the Smart Grid-Layout for CF7, it introduces a new tag called dynamic_dropdown. This is is what you want to use. The dynamic_dropdown creates a select field and allows you to populate the field options using either a taxonomy, titles of a post type, or a filter. You want to use the filter option to actually construct the options as per your requirement. The tag popup window is self explanatory, however if you get stuck post a comment below and I'll give you some more tips.
Using the following dynamic_dropdown tag,
[dynamic_select workshop-date-select class:select2 "source:filter"]
it creates a <select name="workshop-date-select"> dropdown field which will be converted into a select2 jquery field on the front end, and its values dynamically created using the following function placed in the functions.php file,
add_filter('cf7sg_dynamic_dropdown_custom_options', 'filter_options',10,3);
function filter_options($options, $field_name, $form_key){
/*first we verify if this is the right field from the right form
in case multiple forms with similar fieldd exiss.
the $form_key is a unique key exposed by the Smart Grid-layout plugin
instead of using form IDs to make forms and code more portable across servers.*/
if($form_key != 'my-form' && $field_name != 'workshop-date-select') return $options;
$options = array();
//load your options programmatically, as $value=>$name pairs.
$args = array (
'post_type' => 'workshop',
'post_status' => 'publish',
'orderby' => 'name',
'order' => 'ASC',
'numberposts' => - 1,
);
$workshops = get_posts( $args );
foreach($workshops as $workshop){
$val = $workshop->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $workshop->ID);
$options[$val]=$val;
}
return $options;
}
this will create the desired dropdown select field in the front end.
NOTE of CAUTION: I would populate the option values as the workshop post ID rather than the same text as the option label. When the form is submitted the value of the post ID can be used to populate the notification email with the desired workshop title and date. This gives more flexibility to expand the reported information in the future.

WordPress get_template_part pass variable

Is there a way of passing a variable to get_template_part() in wordpress:
<?php get_template_part( 'element-templates/front', 'top' ); ?>
<?php get_template_part( 'element-templates/front', 'main' ); ?>
In the front-top.php and front-main.php (which the above is calling) I need to access numeric variables (a different one for each section). Is there a way of passing a variable to each of the calls above?
Thank you
Using WordPress 5.5+
As of WordPress 5.5, passing variables via get_template_part is part of core.
Starting in WordPress 5.5, the template loading functions will now
allow additional arguments to be passed through to the matched
template file using a new $args parameter.
get_template_part( string $slug, string $name = null, array $args = null )
Example:
get_template_part( 'template-parts/featured-image', null,
array(
'class' => 'featured-home',
'data' => array(
'size' => 'large',
'is-active' => true,
)
)
);
and then in the included file (i.e. template-parts/featured-image.php), you can either just display the variables (as per above example):
if ( $args['class'] ) {
echo $args['class'];
}
or
echo $args['data']['size'];
Alternatively, setup defaults first, using wp_parse_args:
// Setup defaults
$array_defaults = array(
'class' => 'featured',
'data' => array(
'size' => 'medium',
'is-active' => false,
)
);
$args = wp_parse_args($args, $array_defaults );
<div class="widget <?php echo esc_html( $args['class'] ); ?>">
<?php echo esc_html( $args['data']['size'] ); ?>
</div>
To be backwards compatible in your theme, you should probably also check the current WordPress version.
Using set_query_vars
The original answer to this question was to use set_query_var
In your theme:
<?php
set_query_var( 'my_var_name', 'my_var_value' );
get_template_part( 'template-parts/contact' );
?>
In the template part:
<?php
$newValue = get_query_var( 'my_var_name' );
if ( $newValue ) {
// do something
}
?>
The core get_template_part() function doesn't support the passing of variables. It only accepts two parameters, slug and name. While there is no built-in solution to this problem, the best approach is to create a function that closely mimics get_template_part() to handle it.
Normally I would create a function that just takes the name of the template file and the variables I want to pass in as an array. In your example however, you're using both arguments for get_template_part() already which means you'll need a slightly more complex function. I'm going to post both versions below.
Simplified Version - Name (slug) and Data
function wpse_get_partial($template_name, $data = []) {
$template = locate_template($template_name . '.php', false);
if (!$template) {
return;
}
if ($data) {
extract($data);
}
include($template);
}
Usage example: wpse_get_partial('header-promotion', ['message' => 'Example message']);
This would load up a file named header-promotion.php with $message available inside of it. Since the second parameter is an array, you can pass in as many variables as you need.
Copy of get_template_part - adding a third parameter
If you don't need both $slug and $name when you call get_template_part(), you probably want the simplified version. For those that do, here's the more complex option.
function wpse_get_template_part($slug, $name = null, $data = []) {
// here we're copying more of what get_template_part is doing.
$templates = [];
$name = (string) $name;
if ('' !== $name) {
$templates[] = "{$slug}-{$name}.php";
}
$templates[] = "{$slug}.php";
$template = locate_template($templates, false);
if (!$template) {
return;
}
if ($data) {
extract($data);
}
include($template);
}
Usage example: wpse_get_template_part('header-promotion', 'top', [$message => 'Example message']);
Neither function is a perfect copy of get_template_part(). I've skipped all of the extra filters the core function uses for the sake of simplicity.
What about globals or query vars
Globals are pretty commonplace in WordPress but are generally best avoided. They will work but start to get messy when you use the same template part more than once on a single page.
Query vars (get_query_var() / set_query_var()) aren't made for that purpose. It's a hacky workaround that can introduce unintended side-effects.
As of WordPress 5.5, you're be able to achieve this using the following method:
<?php
get_template_part(
'my-template-name',
null,
array(
'my_data' => array(
'var_one' => 'abc',
'var_two' => true,
)
)
);
In your template, you can then parse the date and escape it in the following way:
<?php
$args = wp_parse_args(
$args,
array(
'my_data' => array(
'var_one' => 'xyz', // default value
'var_two' => false, // default value
)
)
);
?>
<?php echo esc_html( $args['my_data']['var_one'] ); ?>
you can pass data to tempalte part via Global varible
like this
$var = 'smoe data here';
<?php get_template_part( 'element-templates/front', 'top' ); ?>
then in your template part file use
<?php
global $var;
echo $var; // smoe data here
?>
Like mentioned by thetwopct - since WP 5.5, you can pass $args to the get_template_part function like so:
$value_of_first = 'pizza';
$value_of_second = 'hamburger';
$value_of_first = 'milkshake';
$args = array(
'first' => $value_of_first,
'second' => $value_of_second,
'third' => $value_of_third,
)
get_template_part( 'element-templates/front', 'top', $args );
then, in element-templates/front-top.php get the vars like so:
[
'first' => $value_of_first,
'second' => $value_of_second,
'third' => $value_of_third,
] = $args;
echo 'I like to eat '.$value_of_first.' and '.$value_of_second.' and then drink '.$value_of_third.';
// will print "I like to eat pizza and hamburger and then drink milkshake"
Note: the method described above for getting the vars in the template file uses associative array restructuring, available only from PHP 7.1. You can also do something like:
echo 'I like to eat '.$args[value_of_first].' and ...
A quick and dirty workaround can be made using PHP Constants:
In your theme:
define("A_CONSTANT_FOR_TEMPLATE_PART", "foo");
get_template_part("slug", "name" );
Now in slug-name.php template file you can use the A_CONSTANT_FOR_TEMPLATE_PART constant. Be sure not override system constants by using a custom prefix for your constant name.
In your template part file:
echo A_CONSTANT_FOR_TEMPLATE_PART;
You should see "foo".

Custom API Endpoint get data from category

im pretty stuck.. Im trying to get all post data from a specific category ID, using Wordpress REST API. But it dosen't output the content, only the ID & Title.. Cant see what I am doing wrong..
Heres the code:
/* Register Route http://dev.mpblogg.se/wp-json/api/v1/feedposts/id */
add_action( 'rest_api_init', function () {
register_rest_route( 'api/v1', '/feedposts/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'getAllPostsfromCategory',
));
});
/* Get all posts from the specific Caetgory */
function getAllPostsfromCategory( $data ) {
$secret = '2lpMh5EHaEiavhMONpWD';
$qs = explode('&', $_SERVER['QUERY_STRING'])[0];
$qs = explode('=', $qs)[1];
if($qs != $secret){
return false;
}
$posts = get_posts( array(
'category' => $data['id'],
));
$returnArray = array();
foreach($posts as $post) {
array_push($returnArray, array(
'id' => $post->ID,
'title' => $post->post_title,
'content' => $post->post_content
));
}
// die();
if(empty($posts)){
return null;
}
return $returnArray;
}
The JSON output looks like this:
After changing to array_push($returnArray,$post); it looks like this:
Okay... here's a clue that I got from the array_push image that you shared. The last string of the JSON output reads:
"filer": "raw"
This means that the resultant value would be stored as a raw, unfiltered content of the post.
So, you can try adding apply_filters() to the extracted content and see if it helps you display the required content.
$content = apply_filters('the_content', $content);
$content = str_replace(']]>', ']]>', $content);
echo $content;
This is used to apply the content filters to raw unfiltered post content, which usually comes from the use of $post->post_content .
As usual the answer why it didnt work is so dumb. Im not using the the_content.. Im using a custom field from ACF called post_excerpt. So I just added:
'excerpt' => get_field('post_excerpt', $post->ID),
Now it works.. Sorry all, but thank's for all the help.

Custom product attributes is blank even though I add it [duplicate]

The products in my clients website require certain attributes which I have added via Products -> Attributes in the Wordpress administration. In this import script I'm coding I need to use the function update_post_meta($post_id, $meta_key, $meta_value) to import the proper attributes and values.
Currently I have the function like so:
update_post_meta( $post_id, '_product_attributes', array());
However I'm not sure how to properly pass along the attributes and their values?
Right so it took me a while to figure it out myself but I finally managed to do this by writing the following function:
// #param int $post_id - The id of the post that you are setting the attributes for
// #param array[] $attributes - This needs to be an array containing ALL your attributes so it can insert them in one go
function wcproduct_set_attributes($post_id, $attributes) {
$i = 0;
// Loop through the attributes array
foreach ($attributes as $name => $value) {
$product_attributes[$i] = array (
'name' => htmlspecialchars( stripslashes( $name ) ), // set attribute name
'value' => $value, // set attribute value
'position' => 1,
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
// Example on using this function
// The attribute parameter that you pass along must contain all attributes for your product in one go
// so that the wcproduct_set_attributes function can insert them into the correct meta field.
$my_product_attributes = array('hdd_size' => $product->hdd_size, 'ram_size' => $product->ram_size);
// After inserting post
wcproduct_set_attributes($post_id, $my_product_attributes);
// Woohay done!
I hope this function will help other people if they need to import multiple attributes pro-grammatically in WooCommerce!
I tried Daniel's answer, and it didn't work for me. It might be that the Wordpress/Woocommerce code has changed since, or perhaps I didn't quite understand how to do it, but either way that code did nothing for me. After a lot of work using it as a base, however, I came up with this snippet of code and put it on my theme's functions.php:
function wcproduct_set_attributes($id) {
$material = get_the_terms( $id, 'pa_material');
$material = $material[0]->name;
// Now update the post with its new attributes
update_post_meta($id, '_material', $material);
}
// After inserting post
add_action( 'save_post_product', 'wcproduct_set_attributes', 10);
With this, I can take what I set as "material" on my WooCommerce install as a custom attribute and add it to the formal meta as _material. This in turn allows me to use another snippet of code so the WooCommerce search function extends to meta fields, meaning I can search for a material in the WooCommerce search field and have all items with that material appear.
I hope this is useful to somebody.
#Daniels's answer works, won't decide on right or wrong, however if you want to add the values as a taxonomy term under attributes you have to adapt the code as below (set is_taxonomy = 1). Otherwise Woocommerce sees it as custom meta field(?). It still adds the value under attributes. This will only work for strings. For values that are arrays the code has to be adapted.
Additionally it uses the wp_set_object_terms that #Anand suggests as well. I was using that, because all the documentation I could find led to believe that had to be used. However if one only uses the wp_set_object_terms then I couldn't see the attributes in the edit product screen. Using the information from both answers and reading on the subject resulted in the solution.
You will need to tweak the code for things such as product variations.
/*
* Save Woocommerce custom attributes
*/
function save_wc_custom_attributes($post_id, $custom_attributes) {
$i = 0;
// Loop through the attributes array
foreach ($custom_attributes as $name => $value) {
// Relate post to a custom attribute, add term if it does not exist
wp_set_object_terms($post_id, $value, $name, true);
// Create product attributes array
$product_attributes[$i] = array(
'name' => $name, // set attribute name
'value' => $value, // set attribute value
'is_visible' => 1,
'is_variation' => 0,
'is_taxonomy' => 1
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
Then call the function:
$custom_attributes = array('pa_name_1' => $value_1, 'pa_name_2' => $value_2, 'pa_name_3' => $value_3);
save_wc_custom_attributes($post_id, $custom_attributes);
Thank you for posting the code Daniel & Anand. It helped me a great deal.
Don't know if this is the "correct" way to do this... But I needed a function to add ACF repeater fields with a date value as a attribute on post save, so this was the function I came up with:
add_action( 'save_post', 'ed_save_post_function', 10, 3 );
function ed_save_post_function( $post_ID, $post, $update ) {
//print_r($post);
if($post->post_type == 'product')
{
$dates = get_field('course_dates', $post->ID);
//print_r($dates);
if($dates)
{
$date_arr = array();
$val = '';
$i = 0;
foreach($dates as $d)
{
if($i > 0)
{
$val .= ' | '.date('d-m-Y', strtotime($d['date']));
}
else{
$val .= date('d-m-Y', strtotime($d['date']));
}
$i++;
}
$entry = array(
'course-dates' => array(
'name' => 'Course Dates',
'value' => $val,
'position' => '0',
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
)
);
update_post_meta($post->ID, '_product_attributes', $entry);
}
}
}
Hope this helps someone.

Accessing Advanced Custom Fields by Page Name

I am trying to retrieve all advanced custom fields tied to a particular page. This is different than iterating through posts, I am familiar with the following:
$posts = get_posts(array(
'post_type' => 'post_name',
'meta_key' => 'color',
'meta_value' => 'red'
));
However this method is specific to posts and does not allow me to retrieve all ACF by page name.
I appreciate any suggestions on how to accomplish this.
The are too ways to do this that come to mind...
1. Using the Loop
Using WP_Query you can do something like this...
<?php
// WP_Query arguments
$args = array (
'pagename' => 'homepage',
);
// The Query
$query = new WP_Query( $args );
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
the_field( "field_name" );
}
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
?>
In place of the 'homepage' in 'pagename' => 'homepage', you want to put the page slug of your page. And of course in place of the_field( "text_field" ); you want to add your fields/content.
You can also query by Page ID and some other parameters. You can find all other parameters that you can use here:
https://codex.wordpress.org/Class_Reference/WP_Query#Post_.26_Page_Parameters
2. Adding second parameter to the_field() function
More simple way, without custom loop, is just to use ACF's built-in the_field() function with the $post->ID parameter added as a second parameter.
<?php the_field('field_name', 123);
This might be the way to go since you want to show the content of only one page, and therefore don't really need to loop.
Reference: http://www.advancedcustomfields.com/resources/how-to-get-values-from-another-post/
You can use ACF's get_fields() function -
<?php $fields = get_fields( $post->ID ); ?>
You could then loop through them or simply print the array for testing.
http://www.advancedcustomfields.com/resources/get_fields/

Resources