WooCommerce do_action in shortcode is messing up page layout - php

I have created a shortcode to display products of a specific product category (combined with a few ACF fields). All works great so use the code below for you own benefit.
The shortcode looks like this: [yl_get_products cat_id='51' order='ASC' template='1'] As you can see I've added template='1' so you can add a new layout later if you prefer.
Oke, so what's my problem:
When I want to add the ADD-TO-CART button (together with my product add-ons) I need something like:
do_action( 'woocommerce_' . $product->get_type() . '_add_to_cart' ); within my shortcode.
or
do_action( 'woocommerce_single_product_summary' ); (and then remove all the not needed actions)
The result is that it indeed shows the whole add-to-cart output with add-on options etc. but it always displays on top of the page (in stead of the modal) and also any page styling is completely ignored.
I believe I have had this before and I thought it had to do something with echo return return = return .= but I can't get it right.
So my actual question is:
How can I add one to the actions above in my product loop shortcode without messing up the layout?
Here's my code:
// Get a dish category via shortcode
function yl_get_products_shortcode( $atts ) {
$atts = shortcode_atts( array(
'cat_id' => '',
'orderby' => '',
'order' => '',
'template' => '',
), $atts );
$products = new WP_Query(array(
'post_type' => 'product',
'tax_query' => array( array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $atts['cat_id'],
// 'include_children' => false // or true (optional)
)),
'orderby' => $atts['orderby'],
'order' => $atts['order'],
'post_status' => 'publish',
'posts_per_page' => -1
));
if ( $products->have_posts() ) {
while ( $products->have_posts() ) {
$products->the_post();
if ($atts['template'] == '1') {
global $product;
$id = get_the_ID();
$product = wc_get_product( $id );
$name = $product->get_title();
$short_description = $product->get_short_description();
$description = $product->get_description();
$rating_count = $product->get_rating_count();
$rating_average = number_format($product->get_average_rating() * 20, 0) . '%';
$review_count = $product->get_review_count();
$price = $product->get_price();
$image_url = wp_get_attachment_url( $product->get_image_id() );
$description_nl = get_field('description_nl');
$title_en = get_field('title_en');
$description_en = get_field('description_en');
$allergens = get_field('allergens');
$specifics = get_field('specifics');
$output .= '
<li>
<div class="uk-grid-small" uk-grid>';
if ($product->is_in_stock()) {
$output .= '
<div class="uk-width-auto">
<a href="#product-' . $id . '" class="uk-button uk-button-small uk-button-primary" uk-toggle>
<span uk-icon="icon: cart"></span>
</a>
</div>';
}
if (!empty($allergens)) {
$output .= '
<div class="uk-width-auto">
<a href="#allergens-' . $id . '" uk-toggle>
<span uk-icon="icon: info"></span>
</a>
</div>';
}
$output .= '
<div class="uk-width-expand">
<p class="uk-h6 uk-margin-remove">
' . $name;
if (!empty($specifics)) {
foreach ($specifics as $specific) {
$output .= '
<img src="/wp-content/uploads/network/images/food-icons/icon-' . str_replace(' ', '-', $specific) . '.svg" width="16" uk-tooltip="' . $specific . '">';
}
}
$output .= '
</p>
<p class="uk-margin-remove">
' . $description_nl;
if ($short_description) {
$output .= '<br />' . $short_description;
}
$output .= '
</p>
</div>
<div class="uk-width-auto uk-h6">
€ ' . $price . '
</div>
</div>';
if (!empty($allergens) || !empty($specifics)) {
$output .= '
<div id="allergens-' . $id . '" uk-modal="center: true">
<div class="uk-modal-dialog uk-modal-body">
<button class="uk-modal-close-default" type="button" uk-close></button>
<h3 class="uk-modal-title uk-margin-small uk-text-truncate">
' . $name;
if (!empty($specifics)) {
foreach ($specifics as $specific) {
$output .= '
<img src="/wp-content/uploads/network/images/food-icons/icon-' . str_replace(' ', '-', $specific) . '.svg" width="16" uk-tooltip="' . $specific . '">';
}
}
$output .= '
</h3>
<p class="uk-margin-small">' . __( 'Below you will find an overview of the allergens that are in this dish. For more information you can always contact our service staff.', 'yorlinq' ) . '</p>
<div uk-alert>
<div class="uk-grid-small uk-child-width-1-2#s" uk-grid>';
foreach ($allergens as $allergen) {
$output .= '
<div>
<div class="uk-grid-small uk-flex-middle" uk-grid>
<div class="uk-width-1-4">
<img src="/wp-content/uploads/network/images/food-icons/icon-' . str_replace(' ', '-', $allergen) . '.svg">
</div>
<div class="uk-width-3-4">
' . $allergen . '
</div>
</div>
</div>';
}
$output .= '
</div>
</div>
</div>
</div>';
}
if ($product->is_in_stock()) {
$output .= '
<div id="product-' . $id . '" uk-modal="center: true">
<div class="uk-modal-dialog uk-modal-body">
<button class="uk-modal-close-default" type="button" uk-close></button>
<h3 class="uk-modal-title uk-margin-small uk-text-truncate">
' . $name;
if (!empty($specifics)) {
foreach ($specifics as $specific) {
$output .= '
<img src="/wp-content/uploads/network/images/food-icons/icon-' . str_replace(' ', '-', $specific) . '.svg" width="16" uk-tooltip="' . $specific . '">';
}
}
$output .= '
</h3>
' . $description;
// Here is where the action sould appear
$output .= '
</div>
</div>';
}
$output .= '
</li>';
}
};
return '<ul class="uk-list uk-list-divider">' . $output . '</ul>';
}
}
add_shortcode('yl_get_products','yl_get_products_shortcode');

I would recommend using an output buffer for storing echo output as a string. The stored content could be easily appended to the shortcode output:
function yl_get_products_shortcode( $atts ) {
// ... your logic
add_action( 'woocommerce_' . $product->get_type() . '_add_to_cart', function () {
// You could remove any action you want
// remove_action( 'xxx', 'xxx', priority );
}, 1 );
ob_start();
do_action( 'woocommerce_' . $product->get_type() . '_add_to_cart' );
$add_to_cart_content = ob_get_clean();
return '<ul class="uk-list uk-list-divider">' . $output . '</ul>' . $add_to_cart_content;
}

Related

How to fix Warning: Use of undefined constant active - assumed 'active' (this will throw an Error in a future version of PHP)

I'm currently working on a WirdPress Theme project using Bootstrap v5.0.2 and PHP 7.3.28.
I'm tryng to insert the Bootstrap Carousel Component in a custom widget but when I debug the code I recive this "Warning: Use of undefined constant active - assumed 'active' (this will throw an Error in a future version of PHP) in ... on line 70"
This is the line that give me the error:
echo ' class="';if ( $the_query->current_post == 0 ) : active ;endif; '"> ';
I try to change active in $active or 'active' but it doen't works.
Because I'm a newbie in PHP I don't understand what I'm doing wrong.
I hope someone can help me to solve this problem.
Thanks
This is the whole code:
<?php
// Register and load the widget
function tabulas_slider_widget() {
register_widget( 'Tabulas_Slider_Widget' );
}
add_action( 'widgets_init', 'tabulas_slider_widget' );
// Creating the widget
class Tabulas_Slider_Widget extends WP_Widget {
/**
* Register widget with WordPress.
*/
public function __construct() {
parent::__construct(
// Base ID of widget
'Tabulas_Slider_Widget',
// Widget name will appear in UI
esc_html__('Last Post Slider', 'tabulas'),
// Widget description
array( 'description' => esc_html__( 'Display the 3 last post published with featured image in the form of a Slider', 'tabulas'), )
);
}
/**
* Front-end display of widget.
*
* #see WP_Widget::widget()
*
* #param array $args Widget arguments.
* #param array $instance Saved values from database.
*/
public function widget( $args, $instance ) {
// WP_Query arguments
$args = array(
'post_type' => 'post',
'posts_per_page' => 3,
);
// The Query
$the_query = new WP_Query ( $args );
echo ' <div id="carouselExampleCaptions" ';
echo ' class="carousel slide" ';
echo ' data-bs-ride="carousel" ';
echo ' data-bs-interval="10000"> ';
echo ' <div class="carousel-indicators"> ';
if ( $the_query->have_posts() ) :
echo $args['before_widget'];
if ( $title ){
echo $args['before_title'] . $title . $args['after_title'];
}
echo ' <ol class="carousel-indicators"> ';
while ( $the_query->have_posts() ) : $the_query->the_post();
echo ' <li data-target="#ExampleCarouselID" ';
echo ' data-slide-to="';$the_query->current_post;'" ';
echo ' class="';if ( $the_query->current_post == 0 ) : active ;endif; '"> ';
echo ' </li> ';
endwhile;
echo ' </ol> ';
rewind_posts();
echo ' <button type="button" ';
echo ' data-bs-target="#carouselExampleCaptions" ';
echo ' data-bs-slide-to="0" ';
echo ' class="active" ';
echo ' aria-current="true" ';
echo ' aria-label="Slide 1">';
echo ' </button> ';
echo '<button type="button" ';
echo ' data-bs-target="#carouselExampleCaptions" ';
echo ' data-bs-slide-to="1" ';
echo ' aria-label="Slide 2">';
echo ' </button> ';
echo '<button type="button" ';
echo ' data-bs-target="#carouselExampleCaptions" ';
echo ' data-bs-slide-to="2" ';
echo ' aria-label="Slide 3">';
echo '</button>';
echo '</div>';
echo ' <div class="carousel-inner"> ';
while ( $the_query->have_posts() ) : $the_query->the_post();
$thumbnail_id = get_post_thumbnail_id();
$thumbnail_url = wp_get_attachment_image_src( $thumbnail_id, 'full', true );
$thumbnail_meta = get_post_meta( $thumbnail_id, '_wp_attatchment_image_alt', true );
echo ' <div class="carousel-item ';
if ( $the_query->current_post == 0 ) : active ;endif; '"> ';
if ( has_post_thumbnail() ) {
echo '<a href="';the_permalink(); echo '">';
the_post_thumbnail('full');
echo '</a>';
}
echo '<div class="carousel-caption d-none d-md-block">';
echo '<h5>';
the_title();
echo '</h5>';
echo '</div>';
echo '</div>';
endwhile;
wp_reset_query();
echo '</div>';
echo '<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide="prev">';
echo '<span class="carousel-control-prev-icon" aria-hidden="true">';
echo '</span>';
echo' <span class="visually-hidden">';esc_html_e( 'Previous', 'tabulas' );
echo '</span>';
echo '</button>';
echo '<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleCaptions" data-bs-slide="next">';
echo '<span class="carousel-control-next-icon" aria-hidden="true">';
echo '</span>';
echo '<span class="visually-hidden">';esc_html_e( 'Next', 'tabulas' );
echo '</span>';
echo '</button>';
echo '</div>';
echo $args['after_widget'];
wp_reset_postdata();
endif;
}
You must echo 'active' and end of line:
echo ' class="';if ( $the_query->current_post == 0 ) : echo 'active' ;endif; echo '"> ';

How to rewrite an echo function to a return value for a Wordpress theme

I am new to PHP and I am glad that I have written the following function (which works as it should) on my own so far:
function get_latest_posts() {
echo '<div class="latest-posts">';
echo '<div class="brick_list">';
$args = array(
post_type => 'post',
posts_per_page => 3
);
$latestposts_query = new WP_Query($args);
if ( $latestposts_query->have_posts() ) : while ( $latestposts_query->have_posts() ) : $latestposts_query->the_post();
echo ' <div ';
post_class("brick_item" . $termString );
echo ' onclick="location.href=\'';
the_permalink();
echo ' \'"> ';
echo ' <div class="brick_item-image"> ';
if ( has_category( 'sample' ) ) {
echo ' <img src="/wp-content/uploads/placeholder_1.png" /> ';
} elseif ( has_post_thumbnail() ) {
the_post_thumbnail();
} else {
echo ' <img src="/wp-content/uploads/placeholder_2.png" /> ';
}
echo ' </div> ';
echo ' <div class="brick_item-header"> ';
echo ' <h4><a href=" ';
the_permalink();
echo ' "> ';
the_title();
echo ' </a></h4> ';
echo ' </div> ';
echo ' </div> ';
endwhile; else :
get_template_part('template_parts/content','error');
endif;
wp_reset_postdata();
echo '</div>';
echo '</div>';
}
add_shortcode( 'get_latest_posts', 'get_latest_posts' );
But now I definitly need your help...
As you can see I want to use this function in a shortcode. Currently it displays first on my page, and Google says, this is because I am echoing the content and I would need to give a return value.
How do I do this?? Is it just replacing the word "echo" with the word "return" ? I have no idea...
I have condensed a few statements together for readability but here's what that would look like:
function get_latest_posts() {
$return = '<div class="latest-posts"><div class="brick_list">';
$args = array(
post_type => 'post',
posts_per_page => 3
);
$latestposts_query = new WP_Query($args);
if ( $latestposts_query->have_posts() ) : while ( $latestposts_query->have_posts() ) : $latestposts_query->the_post();
$return .= ' <div ' . post_class("brick_item" . $termString ) . ' onclick="location.href=\'' . get_permalink() . '\'"> ';
$return .= '<div class="brick_item-image">';
if ( has_category( 'sample' ) ) {
$return .= '<img src="/wp-content/uploads/placeholder_1.png" />';
} elseif ( has_post_thumbnail() ) {
$return .= get_the_post_thumbnail();
} else {
$return .= '<img src="/wp-content/uploads/placeholder_2.png" />';
}
$return .= '</div> <div class="brick_item-header"> <h4>' . the_title('','',false) . '</h4></div></div>';
endwhile; else :
get_template_part('template_parts/content','error');
endif;
wp_reset_postdata();
$return .= '</div></div>';
return $return;
}
add_shortcode( 'get_latest_posts', 'get_latest_posts' );

how to add pagination WordPress in functions.php

The blog have over 100 posts page. I would like to add pagination in WordPress functions.php but how do I add the code in
functions.php
/**
* Shortcode News
*/
add_shortcode( 'news', 'new_bubble' );
function new_bubble(){
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => '20',
'paged' => $paged
);
$query = new WP_Query( $args );
if( $query->have_posts() ){
$string .= '<div class="row">';
while( $query->have_posts() ){
$query->the_post();
$string .= '<div class="col-md-4">';
$string .= '<div class="card">';
$string .= '<a href="' . get_the_permalink() . '">';
$string .= '<div class="card-img" style="background-image: url(' . get_the_post_thumbnail_url() . ');">';
$string .= '</div>';
$string .= '</a>';
$string .= '<div class="card-body">';
$string .= '<p class="post-date">' . get_the_date( 'j F Y' ) . '</p>';
$string .= '<p class="post-title">';
$string .= '<a href="' . get_the_permalink() . '">';
$string .= '' . get_the_title() . '';
$string .= '</a>';
$string .= '</p>';
$string .= '<div class="post-footer">';
$string .= '<div class="author">';
$string .= ''. get_avatar( get_the_author_email(), '50' ) . '';
$string .= '<div class="author-meta">';
$string .= '<h5 class="author-post-name">By ' . get_the_author() . '</h5>';
$string .= '</div>';
$string .= '</div>';
$string .= '</div>';
$string .= '</div>';
$string .= '</div>';
$string .= '</div>';
}
$string .= '</div>';
}
wp_reset_postdata();
return $string;
}
Everything is work fine but I would like to add pagination button

How to fix the problem with the_content filter

I want to add shortcode that has information about my custom post after the_content but when i add the code it shown before the_content
Here is my code
<?php
function foobar_func() { ?>
<h3>Title : </h3>
<ul>
<li>foo : </li>
</ul>
<?php }
add_shortcode( 'project_information', 'foobar_func' );
function wpdev_before_after( $content ) {
$beforecontent = '';
if ( is_single() ) {
$aftercontent = '[project_information]';
} else {
$aftercontent = '';
}
$fullcontent = $beforecontent . $content . $aftercontent;
return $fullcontent;
}
add_filter('the_content', 'wpdev_before_after');
?>
My foobar_func should be like this and i have more custom taxonomy to list and if I use variable to show them my code will be very messy
function foobar_func() { ?>
<h3>Title : </h3>
<ul>
<li>foo : <?php
$terms = wp_get_post_terms( $post->ID, 'taxonomy', $args );
foreach( $terms as $term ) {
if ( end($terms) == $term ){
echo '' . $term->name . '';
} else {
echo '' . $term->name . ' , ';
}
}
?></li>
</ul>
<?php }
Try assigning the html to a variable and return it in your foobar_func()
function foobar_func() {
$html = "
<h3>Title : </h3>
<ul>
<li>foo :
";
$terms = wp_get_post_terms( $post->ID, 'taxonomy', $args );
foreach( $terms as $term ) {
if ( end($terms) == $term ){
$html .= '' . $term->name . '';
} else {
$html .= '' . $term->name . ' , ';
}
}
$html .= "
</li>
</ul>";
return $html;
}

How can i get first image if the post has no post thumbnail in wordpress

I have created the sidebar widget for popular, recent and most commented posts in my theme. I have some posts which don't contain the image thumbnail.
This is the popular query posts for 5 posts in my widget
<?php if (!empty($popular_posts)) { ?>
<div class="tab-pane fade in active" id="popular">
<div class="row">
<!-- ********************************************** -->
<!-- Popular Posts Tab -->
<!-- ********************************************** -->
<?php
$YPE_options = get_option( 'YPE_sidebar_option_name' );
$popular = new WP_Query( array(
'posts_per_page' => $popular_limit,
'meta_key' => 'post_views_count', // this is function within functions.php for counting post veiews
'orderby' => 'meta_value_num',
'order' => 'DESC'
));
while ( $popular->have_posts() ) : $popular->the_post();
$html = '<article>';
$html .= '<section class="bootstrap-nav-thumb">';
$html .= '<p>';
$html .= '<a href="' . get_permalink() . '">';
$html .= get_the_post_thumbnail(get_the_ID(), array('class' => 'img-responsive '.$YPE_options['YPE_sidebar_PRC_thumb_style'].''));
$html .= '</a>';
$html .= '</p>';
$html .= '</section>';
$html .= '<aside class="bootstrap-title-info">';
$html .= '<p>';
$html .= ''.get_the_title().'';
$html .= '</p>';
$html .= '<p class="text-muted">' . get_the_date() . '||'. getPostViews(get_the_ID()) . '</p>';
$html .= '</aside>';
$html .= '</article>';
echo $html;
endwhile;
?>
</div> <!-- End row of popular posts -->
</div> <!-- End tab-pane of popular posts -->
<?php } ?>
how can i add conditional statement to this code
$html .= '<a href="' . get_permalink() . '">';
$html .= get_the_post_thumbnail(get_the_ID(), array('class' => 'img-responsive '.$YPE_options['YPE_sidebar_PRC_thumb_style'].''));
$html .= '</a>';
Note: i want to say if has post thumbnail put the posts thumbnail and if not has the thumbnail put the first image instead of the post thumbnail
$thumb = get_the_post_thumbnail(get_the_ID());
if(!empty($thumb))
$image = $thumb;
else {
$image = '<img src="';
$image .= catch_that_image();
$image .= '" alt="" />'; }
And put your function as
function catch_that_image() {
global $post, $posts;
$first_img = '';
ob_start();
ob_end_clean();
$output = preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post->post_content, $matches);
$first_img = $matches [1] [0];
if(empty($first_img)){ //Defines a default image
$first_img = "/images/default.jpg";
}
return $first_img;
}
Something like this could work:
$html .= '<a href="' . get_permalink() . '">';
if ( has_post_thumbnail() ) {
$html .= get_the_post_thumbnail(get_the_ID(), array('class' => 'img-responsive '.$YPE_options['YPE_sidebar_PRC_thumb_style'].''));
} else {
$html .= "<img src='". echo wp_get_attachment_image_src(0,'thumbnail') .'" class="img-responsive ' .$YPE_options['YPE_sidebar_PRC_thumb_style'].' " />';
};
html .= '</a>';

Categories