Wordpress improve shortcode with more parameters - wordpress

when you are a new designer and start working with several content editors in wordpress, the first thing you realize is that it is not easy to find the functions you want exactly.
plugin editors can't think of everything.. and especially extract information to display them everywhere in the desired and consistent manner.
that's why wordpress shortcodes exist. but you have to master them.. first! (which is precisely my handicap currently)
Grab your cup of coffee β˜• and admire the detailed visual of today's issue
It will be very short and precise,
before starting look at what taxonomies we have in our post..
my current code allows me to do figure 1, as you can see it quickly becomes limited when you try to be .. more creative
add_shortcode( 'parent-child', 'taxonomy_hierarchy' );
function taxonomy_hierarchy( $atts ){
// Don't extract, rather parse shortcode params with defaults.
$atts = shortcode_atts( array(
'link' => 'true',
'taxonomy' => 'property_city'
), $atts, 'parent-child' );
// Check the $atts parameters and their typecasting.
//var_dump( $atts );
global $post;
$terms = wp_get_post_terms( $post->ID, $atts['taxonomy'] );
/* You can pass conditions here to override
* $link based on certain conditions. If it's
* a single post, current user is editor, etc.
*/
ob_start();
foreach( $terms as $term ){
if( $term->parent != 0 ){
$parent_term = get_term( $term->parent, $taxonomy );
if ($atts['link'] !== 'false') {
printf( '%s, ', esc_url( get_term_link($parent_term) ), $parent_term->name );
} else {
echo $parent_term->name . ', ';
}
}
if ($atts['link'] !== 'false') {
printf( '%s', esc_url( get_term_link($term) ), $term->name );
} else {
echo $term->name;
}
}
return ob_get_clean();
}
in this figure 1 we don't need to display "residential" and "rental" it doesn't make sense it's confusing. we don't have control over this.
but..What if I want to test and accomplish figure 2, figure 3 and figure 4
You : but there are already shortcodes what is it???
yes, don't worry, I took care to simulate a logic of things inside shortcodes, maybe that's not exactly how it's going to be. or how things work ..
I prefer to remain cautious and wait for your opinion or solution.
if logic allows, we need to separate the parent and childs values ​​and paste them back as we want
like a puzzle
Something Like πŸ‘€
↑[taxonomy-parent = "name_of_my_taxonomy"]
↓[taxonomy-child = "name_of_my_taxonomy"]
or simply reverse in some cases
←[child-parent] (manhattan, new york)
β†’[parend-child] (new york, manhattan)
note that I used [acf field "name field here"] to invoke a price value, if it is possible to fit it inside our combination or leave it like that?
final word: you can tell I spent some time working out and thinking about this, if only coding was that easy for me I would have done even better. for now that's all I need more flexibility to display information in different ways.

You could consider using an array() instead to store the $parent if it exists, and then the $child which should exist. This would give you the benefit of being able to use array_reverse() to flip the order of the terms based on a parameter saying whether you want the parent or the child first. This gives you the added benefit of being able to convert the array to a string with the implode() function, which you can pass a $glue argument to, to determine whether you want them separated by a space, comma + space, hyphen, slash, etc.
add_shortcode( 'parent-child', 'taxonomy_hierarchy' );
function taxonomy_hierarchy( $atts ){
// Don't extract, rather parse shortcode params with defaults.
$atts = shortcode_atts( array(
'link' => 'true',
'glue' => ', ',
'taxonomy' => 'property_city',
'first' => 'parent',
), $atts, 'parent-child' );
// Check the $atts parameters and their typecasting.
//var_dump( $atts );
global $post;
$terms = wp_get_post_terms( $post->ID, $atts['taxonomy'] );
/* You can pass conditions here to override
* $link based on certain conditions. If it's
* a single post, current user is editor, etc.
*/
$array = array();
foreach( $terms as $term ){
if( $term->parent != 0 ){
$parent_term = get_term( $term->parent, $taxonomy );
if ($atts['link'] !== 'false') {
$array[] = sprintf( '%s', esc_url( get_term_link($parent_term) ), $parent_term->name );
} else {
$array[] = $parent_term->name;
}
}
if( $atts['link'] !== 'false' ){
$array = sprintf( '%s', esc_url( get_term_link($term) ), $term->name );
} else {
$array = $term->name;
}
}
if( $atts['first'] != 'parent' ){
$array = array_reverse( $array );
}
return implode($glue, $array);
}
Doing this should give you the ability to put out shortcodes like:
[parent-child first="child" glue=" - "] // Child - Parent
[parent-child glue="/"] // Parent/Child
Documentation & Function Reference
Function
Linked Description
array_reverse()
Return an array with elements in reverse order
implode()
Join array elements with a string

I think I found a solution but in this case it is no longer a shortcode with parameters.
it's become a bunch of shortcodes with a parameters, at least we have more flexibility now.
I simply cut the code into 3 parts
if you are not afraid to see 😰 very long complicated shortcodes. it's a solution that will help.
but I'm not sure if this is the best practice.
output taxonomy parent, child
/*output taxonomy parent, child*/
add_shortcode( 'parent-child', 'taxonomy_hierarchy' );
function taxonomy_hierarchy( $atts ){
$atts = shortcode_atts( array(
'link' => 'true',
'taxonomy' => 'property_city' // my default taxonomy
), $atts, 'parent-child' );
global $post;
$terms = wp_get_post_terms( $post->ID, $atts['taxonomy'] );
ob_start();
foreach( $terms as $term ){
if( $term->parent != 0 ){
$parent_term = get_term( $term->parent, $taxonomy );
if ($atts['link'] !== 'false') {
printf( '%s, ', esc_url( get_term_link($parent_term) ), $parent_term->name );
} else {
echo $parent_term->name . ', ';
}
}
if ($atts['link'] !== 'false') {
printf( '%s', esc_url( get_term_link($term) ), $term->name );
} else {
echo $term->name;
}
}
return ob_get_clean();
}
output only taxonomy parent
/*output only taxonomy parent*/
add_shortcode( 'parent', 'taxonomy_parent' );
function taxonomy_parent( $atts ){
$atts = shortcode_atts( array(
'link' => 'true',
'taxonomy' => 'property_city' // my default taxonomy
), $atts, 'parent' );
global $post;
$terms = wp_get_post_terms( $post->ID, $atts['taxonomy'] );
ob_start();
foreach( $terms as $term ){
if( $term->parent != 0 ){
$parent_term = get_term( $term->parent, $taxonomy );
if ($atts['link'] !== 'false') {
printf( '%s', esc_url( get_term_link($parent_term) ), $parent_term->name );
} else {
echo $parent_term->name;
}
}
}
return ob_get_clean();
}
output only taxonomy child
/*output only taxonomy child*/
add_shortcode( 'child', 'taxonomy_child' );
function taxonomy_child( $atts ){
$atts = shortcode_atts( array(
'link' => 'true',
'taxonomy' => 'property_city' // my default taxonomy
), $atts, 'child' );
global $post;
$terms = wp_get_post_terms( $post->ID, $atts['taxonomy'] );
ob_start();
foreach( $terms as $term ){
if ($atts['link'] !== 'false') {
printf( '%s', esc_url( get_term_link($term) ), $term->name );
} else {
echo $term->name;
}
}
return ob_get_clean();
}

Related

Add different WordPress excerpt formats to different templates

I added the following code to my functions.php file in WordPress 6.1.1 to display excerpts.
function new_excerpt_length($length) {
return 100;
}
add_filter('excerpt_length', 'new_excerpt_length');
function new_excerpt_more($more) {
return '...';
}
add_filter('excerpt_more', 'new_excerpt_more');
...but I also have a use case to show the full excerpt without a read more link.
On page template 1 I add the below code to display the excerpt:
<?php echo the_excerpt(); ?>
...and it displays the excerpt as per the functions.php file but how do I create a 2nd excerpt without the read more link and apply it to page template 2?
Is there a parameter I can use within the_excerpt(parameter); or can I use something like wp_trim_excerpt https://developer.wordpress.org/reference/functions/wp_trim_excerpt/ maybe?
I came across the below code that is supposed to do what I want
function wpex_get_excerpt( $args = array() ) {
// Default arguments.
$defaults = array(
'post' => '',
'length' => 40,
'readmore' => false,
'readmore_text' => esc_html__( 'read more', 'text-domain' ),
'readmore_after' => '',
'custom_excerpts' => true,
'disable_more' => false,
);
// Apply filters to allow child themes mods.
$args = apply_filters( 'wpex_excerpt_defaults', $defaults );
// Parse arguments, takes the function arguments and combines them with the defaults.
$args = wp_parse_args( $args, $defaults );
// Apply filters to allow child themes mods.
$args = apply_filters( 'wpex_excerpt_args', $args );
// Extract arguments to make it easier to use below.
extract( $args );
// Get the current post.
$post = get_post( $post );
// Get the current post id.
$post_id = $post->ID;
// Check for custom excerpts.
if ( $custom_excerpts && has_excerpt( $post_id ) ) {
$output = $post->post_excerpt;
}
// No custom excerpt...so lets generate one.
else {
// Create the readmore link.
$readmore_link = '' . $readmore_text . $readmore_after . '';
// Check for more tag and return content if it exists.
if ( ! $disable_more && strpos( $post->post_content, '<!--more-->' ) ) {
$output = apply_filters( 'the_content', get_the_content( $readmore_text . $readmore_after ) );
}
// No more tag defined so generate excerpt using wp_trim_words.
else {
// Generate an excerpt from the post content.
$output = wp_trim_words( strip_shortcodes( $post->post_content ), $length );
// Add the readmore text to the excerpt if enabled.
if ( $readmore ) {
$output .= apply_filters( 'wpex_readmore_link', $readmore_link );
}
}
}
// Apply filters and return the excerpt.
return apply_filters( 'wpex_excerpt', $output );
}
Output using:
<?php echo wpex_get_excerpt ( $defaults = array(
'length' => 40,
'readmore' => true,
'readmore_text' => esc_html__( 'read more', 'wpex-boutique' ),
'custom_excerpts' => true,
) ); ?>
...but doesn't seem to workas intended. Outputs the excerpt with no link but the args don't see to work when changed. Would be perfect for my use otherwise. Maybe someone sees how to fix this code?
Thanks

WooCommerce function to display total product sales on site homepage

I am trying to find a function and shortcode to display the total amount of products sold as simply as possible on our website.
Don't want to show product names or any info just a count.
I found this function / shortcode that displays total orders. Just wondering fo anyone can help adapt it to display total products sold?
Thanks so much..
function display_woocommerce_order_count( $atts, $content = null ) {
$args = shortcode_atts( array(
'status' => 'completed',
), $atts );
$statuses = array_map( 'trim', explode( ',', $args['status'] ) );
$order_count = 0;
foreach ( $statuses as $status ) {
// if we didn't get a wc- prefix, add one
if ( 0 !== strpos( $status, 'wc-' ) ) {
$status = 'wc-' . $status;
}
$order_count += wp_count_posts( 'shop_order' )->$status;
}
ob_start();
echo number_format( $order_count );
return ob_get_clean();
}
add_shortcode( 'wc_order_count', 'display_woocommerce_order_count' );

Show Child-pages of Specific Parent on any page in Wordpress

My website is build with alot of parents and childs.
I am currently using the follow function: https://gist.github.com/mprahweb/3c94d9c65b32ec9e3b2908305efd77d5
However it doesnt achieve what i want. I can only use it under the parent.
I want to be able to use a shortcode to list a child-pages for a specfic parent on any page (mainly the homepage)
The dream would be that i could have a shortcode like this:
[wpb_childpages_xxx] where xxx equals the parent page
is this possible?
Here is the modified code:
function wpb_list_child_pages( $atts = array() ) {
$atts = shortcode_atts( array(
'id' => 0,
'slug' => '',
), $atts );
if ( $atts['slug'] ) {
global $wpdb;
$q = $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s", $atts['slug'] );
$post_id = $wpdb->get_var( $q );
if ( ! $post_id ) {
return '';
}
} else {
$post_id = absint( $atts['id'] );
}
$post = get_post( $post_id ); // WP_Post on success.
$childpages = '';
if ( $post && is_post_type_hierarchical( $post->post_type ) ) {
$childpages = wp_list_pages( array(
'child_of' => $post->ID,
'title_li' => '',
'echo' => 0,
) );
}
if ( $childpages ) {
$childpages = '<ul>' . $childpages . '</ul>';
}
return $childpages;
}
add_shortcode( 'wpb_childpages', 'wpb_list_child_pages' );
Using the Shortcode β€” use either id or slug, but if you specify a slug, the id will be ignored:
To show child pages of the current page:
[wpb_childpages /]
To show child pages of any pages:
With the post ID: [wpb_childpages id="{POST_ID} /]
E.g. [wpb_childpages id="123" /]
With the post slug: [wpb_childpages slug="{SLUG} /]
E.g. [wpb_childpages slug="home" /]

Woocommerce recently viewed Products

I have created a recently viewed script which generated a shortcode which I then inserted into my home page.
The script is designed so that people who may have visited my website and left, once they come back can see instantly what products they had been viewing on their last visit.
I have placed the shortcode [woocommerce_recently_viewed_products]
and have generated the shortcode using the following script:
function rc_woocommerce_recently_viewed_products( $atts, $content = null ) {
// Get shortcode parameters
extract(shortcode_atts(array(
"per_page" => '5'
), $atts));
// Get WooCommerce Global
global $woocommerce;
// Get recently viewed product cookies data
$viewed_products = ! empty( $_COOKIE['woocommerce_recently_viewed'] ) ? (array) explode( '|', $_COOKIE['woocommerce_recently_viewed'] ) : array();
$viewed_products = array_filter( array_map( 'absint', $viewed_products ) );
// If no data, quit
if ( empty( $viewed_products ) )
return __( 'You have not viewed any product yet!', 'rc_wc_rvp' );
// Create the object
ob_start();
wc_setcookie( 'woocommerce_recently_viewed', implode( '|', $viewed_products ) );
}
// Get products per page
if( !isset( $per_page ) ? $number = 4 : $number = $per_page )
// Create query arguments array
$query_args = array(
'posts_per_page' => $number,
'no_found_rows' => 1,
'post_status' => 'publish',
'post_type' => 'product',
'post__in' => $viewed_products,
'orderby' => 'rand'
);
// Add meta_query to query args
$query_args['meta_query'] = array();
// Check products stock status
$query_args['meta_query'][] = $woocommerce->query->stock_status_meta_query();
// Create a new query
$r = new WP_Query($query_args);
// If query return results
if ( $r->have_posts() ) {
$content = '<ul class="rc_wc_rvp_product_list_widget">';
// Start the loop
while ( $r->have_posts()) {
$r->the_post();
global $product;
$content .= '<li>
<a href="' . get_permalink() . '">
' . ( has_post_thumbnail() ? get_the_post_thumbnail( $r->post->ID, 'shop_thumbnail' ) : woocommerce_placeholder_img( 'shop_thumbnail' ) ) . ' ' . get_the_title() . '
</a> ' . $product->get_price_html() . '
</li>';
}
$content .= '</ul>';
}
// Get clean object
$content .= ob_get_clean();
// Return whole content
return $content;
}
// Register the shortcode
add_shortcode("woocommerce_recently_viewed_products",
"rc_woocommerce_recently_viewed_products");
Everything seems to have registered. However,when I test this myself. I view a few products, go back to the homepage where the shortcode is registered and I see the text
You have not viewed any product yet!
I can not figure out what might be missing in order to register and show the products which I or a potential customer may have viewed.
Woocommerce only save the recently viewed cookie IF woocommerce_recently_viewed_products WIDGET is ACTIVE! See code in wc-product-functions.php wc_track_product_view() function.
Code to save the cookie always in functions.php:
/**
* Track product views. Always.
*/
function wc_track_product_view_always() {
if ( ! is_singular( 'product' ) /* xnagyg: remove this condition to run: || ! is_active_widget( false, false, 'woocommerce_recently_viewed_products', true )*/ ) {
return;
}
global $post;
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) { // #codingStandardsIgnoreLine.
$viewed_products = array();
} else {
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) ); // #codingStandardsIgnoreLine.
}
// Unset if already in viewed products list.
$keys = array_flip( $viewed_products );
if ( isset( $keys[ $post->ID ] ) ) {
unset( $viewed_products[ $keys[ $post->ID ] ] );
}
$viewed_products[] = $post->ID;
if ( count( $viewed_products ) > 15 ) {
array_shift( $viewed_products );
}
// Store for session only.
wc_setcookie( 'woocommerce_recently_viewed', implode( '|', $viewed_products ) );
}
remove_action('template_redirect', 'wc_track_product_view', 20);
add_action( 'template_redirect', 'wc_track_product_view_always', 20 );
You need to set the cookie when you are viewing a single product page so use something like this where I set the cookie to equal the product ID I just viewed. In your case you'll need to get the cookie value if it exists then append the new product to the list of products.
function set_user_visited_product_cookie() {
global $post;
if ( is_product() ){
// manipulate your cookie string here, explode, implode functions
wc_setcookie( 'woocommerce_recently_viewed', $post->ID );
}
}
add_action( 'wp', 'set_user_visited_product_cookie' );
Below code to set cookie 'woocommerce_recently_viewed' worked for me. Hope it helps other
$Existing_product_id = $_COOKIE['woocommerce_recently_viewed'];
if ( is_product() )
{
$updated_product_id = $Existing_product_id.'|'.$post->ID;
wc_setcookie( 'woocommerce_recently_viewed', $updated_product_id );
}

How to make custom form-tag in contact form 7 required

So i make custom form-tag in contact form 7! It is a drop down with list of my courses and now I want to make it required because that is the main thing in whole form.
So can someone give me a tip how to do that?
When I do the [myCustomField* course-name class:custom-field]
It does not working with *
So if someone can help it will be great!
I have been working on this myself this afternoon and I do not think Mahmoud has added everything that is needed to get the validation working well and the messages showing up.
using what I have learnt from the posts on contact form 7 here:
https://contactform7.com/2015/01/10/adding-a-custom-form-tag
https://contactform7.com/2015/02/27/using-values-from-a-form-tag/
and looking at this file in the plugin: contact-form-7/modules/select.php which helped a lot.
I think this will work better and needs to be added to your functions.php file in your child-theme.
add_action( 'wpcf7_init', 'custom_add_form_tag_myCustomField' );
function custom_add_form_tag_myCustomField() {
wpcf7_add_form_tag( array( 'myCustomField', 'myCustomField*' ),
'custom_myCustomField_form_tag_handler', true );
}
function custom_myCustomField_form_tag_handler( $tag ) {
$tag = new WPCF7_FormTag( $tag );
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
$atts['aria-invalid'] = $validation_error ? 'true' : 'false';
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$myCustomField = '';
$query = new WP_Query(array(
'post_type' => 'CUSTOM POST TYPE HERE',
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
));
while ($query->have_posts()) {
$query->the_post();
$post_title = get_the_title();
$myCustomField .= sprintf( '<option value="%1$s">%1$s</option>',
esc_html( $post_title ) );
}
wp_reset_query();
$myCustomField = sprintf(
'<span class="wpcf7-form-control-wrap %1$s"><select %2$s>%3$s</select>%4$s</span>',
sanitize_html_class( $tag->name ),
$atts,
$myCustomField,
$validation_error
);
return $myCustomField;
}
That is how we create the custom tag. The important differences here are the addition of the $validation_error variables as wells the aria-required and aria-invalid data. It is also important to include the $validation_error in the final output so that we can see the validation messages being created.
Then to finish it off we need to add some validation via filters.
There is no documentation on this yet, but I used the functions from the select.php and altered them to what I needed.
/* Validation filter */
add_filter( 'wpcf7_validate_myCustomField', 'wpcf7_myCustomField_validation_filter', 10, 2 );
add_filter( 'wpcf7_validate_myCustomField*', 'wpcf7_myCustomField_validation_filter', 10, 2 );
function wpcf7_myCustomField_validation_filter( $result, $tag ) {
$tag = new WPCF7_FormTag( $tag );
$name = $tag->name;
if ( isset( $_POST[$name] ) && is_array( $_POST[$name] ) ) {
foreach ( $_POST[$name] as $key => $value ) {
if ( '' === $value ) {
unset( $_POST[$name][$key] );
}
}
}
$empty = ! isset( $_POST[$name] ) || empty( $_POST[$name] ) && '0' !== $_POST[$name];
if ( $tag->is_required() && $empty ) {
$result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
}
return $result;
}
This code should also go in your functions.php file just under the code for the custom CF7 tag.
Here the filter's first string $tag should match with the class that is being generated in the custom CF7 tag so if your custom tag->type = 'myCustomField' then the $tag of the filter must include the name, like so wpcf7_validate_myCustomField as well as the required version of it, wpcf7_validate_myCustomField*.
I hope that helps anyone else looking for this.
If you want even more of the options available from the backend of Contact Form 7 check the select.php file as it lays it out quite nicely on how to get each option and include it.
You can use [select*] to output a required drop-down menu.
[select* course-name include_blank "English" "Math"]
Check https://contactform7.com/checkboxes-radio-buttons-and-menus/
EDIT:
So you have your own shortcode [myCustomField]. To make two versions of your shortcode as [myCustomField] and [myCustomField*] you have to pass both shortcodes to your function as the following:
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_mycustomfield' );
function wpcf7_add_form_tag_mycustomfield() {
wpcf7_add_form_tag( array( 'myCustomField', 'myCustomField*'),
'wpcf7_mycustomfield_form_tag_handler', array( 'name-attr' => true ) );
}
function wpcf7_mycustomfield_form_tag_handler( $tag ) {
$tag = new WPCF7_FormTag( $tag );
if ( empty( $tag->name ) ) {
return '';
}
$atts = array();
$class = wpcf7_form_controls_class( $tag->type );
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$html = sprintf( '<your-tag %s></your-tag>', $atts );
return $html;
}
Then, you can use it:
[myCustomField course-name class:custom-field]
or
[myCustomField* course-name class:custom-field]
References:
https://contactform7.com/2015/01/10/adding-a-custom-form-tag
https://contactform7.com/2015/02/27/using-values-from-a-form-tag/

Resources