I’m making a plugin for Elementor. It must show a product from WooCommerce on the page. Picture, name, price, quantity window, +/- buttons, add to cart button for each product. The quantity window does not work, the quantity 1 initial digit is indicated there, it accepts it, and that’s it. If I enter the number 3, it will not record anything and add 1.
Build
- custom-product-widget.php
- script.js
- style.css
- folder “widgets”:
- class-custom-product-widget.php
The main pludin file custom-product-widget.php:
<?php
/*
Plugin Name: Custom Product Widget for Elementor v1.00000000
Description: Додає віджет для Elementor, який відображає WooCommerce продукти.
Version: 1.00000000
Author: blvckfamily
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
// Connecting the necessary files
function cpw_enqueue_scripts() {
wp_enqueue_style( 'cpw-style', plugin_dir_url( __FILE__ ) . 'style.css' );
wp_enqueue_script( 'cpw-script', plugin_dir_url( __FILE__ ) . 'script.js', array('jquery'), null, true );
}
add_action( 'wp_enqueue_scripts', 'cpw_enqueue_scripts' );
// Widget registration
function cpw_register_widget() {
require_once( plugin_dir_path( __FILE__ ) . 'widgets/class-custom-product-widget.php' );
ElementorPlugin::instance()->widgets_manager->register_widget_type( new Custom_Product_Widget() );
}
add_action( 'elementor/widgets/widgets_registered', 'cpw_register_widget' );
The script.js file:
jQuery(function($) {
$('.product-card').each(function() {
var minusBtn = $(this).find('.minus'),
plusBtn = $(this).find('.plus'),
qtyInput = $(this).find('.qty'),
addToCartBtn = $(this).find('.add-to-cart');
function updateAddToCartButton(qtyInput) {
qtyInput.closest('.product-card').find('.add-to-cart').attr('data-quantity', qtyInput.val());
}
minusBtn.on('click', function () {
var currentVal = parseInt(qtyInput.val());
if (currentVal > 1) {
qtyInput.val(currentVal - 1);
updateAddToCartButton(qtyInput);
}
});
plusBtn.on('click', function () {
var currentVal = parseInt(qtyInput.val());
qtyInput.val(currentVal + 1);
updateAddToCartButton(qtyInput);
});
qtyInput.on('input', function () {
updateAddToCartButton(qtyInput);
});
addToCartBtn.on('click', function() {
var productId = $(this).data('product-id');
var quantity = $(this).siblings('.quantity-box').find('.qty').val();
$.ajax({
url: wc_add_to_cart_params.ajax_url,
type: 'POST',
data: {
action: 'woocommerce_ajax_add_to_cart',
product_id: productId,
quantity: quantity
},
success: function(response) {
if (response.error && response.product_url) {
window.location = response.product_url;
} else {
$(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $this]);
}
}
});
});
});
});
The style.css file:
.custom-product-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.product-card {
text-align: center;
padding: 10px;
border: 1px solid #eee;
margin-bottom: 15px;
}
.product-card img {
max-width: 100%;
height: auto;
}
.product-card h3 {
font-size: 16px;
margin: 10px 0;
}
.product-card .quantity-box {
display: flex;
justify-content: center;
align-items: center;
margin: 10px 0;
}
.product-card .quantity-box input {
width: 50px;
text-align: center;
margin: 0 10px;
}
.product-card .add-to-cart {
background-color: #000;
color: #fff;
padding: 10px 20px;
text-transform: uppercase;
border: none;
cursor: pointer;
}
.product-card .add-to-cart:hover {
background-color: #333;
}
.quantity-box button {
background-color: #ddd;
border: none;
padding: 0 10px;
cursor: pointer;
}
.quantity-box button:hover {
background-color: #ccc;
}
/* Remove arrows from number input */
.quantity-box input[type="number"] {
-moz-appearance: textfield;
-webkit-appearance: none;
appearance: none;
}
.quantity-box input[type="number"]::-webkit-inner-spin-button,
.quantity-box input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
In the folder “widgets”, the file “class-custom-product-widget.php”:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class Custom_Product_Widget extends ElementorWidget_Base {
public function get_name() {
return 'custom_product_widget';
}
public function get_title() {
return __( 'Custom Product Widget', 'cpw' );
}
public function get_icon() {
return 'eicon-product-grid';
}
public function get_categories() {
return [ 'general' ];
}
protected function _register_controls() {
// Add controls here if needed
}
protected function render() {
$args = array(
'post_type' => 'product',
'posts_per_page' => 10
);
$products = new WP_Query( $args );
if ( $products->have_posts() ) {
echo '<div class="custom-product-grid">';
while ( $products->have_posts() ) {
$products->the_post();
global $product;
?>
<div class="product-card">
<?php if ( has_post_thumbnail() ) { ?>
<img src="<?php echo esc_url( get_the_post_thumbnail_url() ); ?>" alt="<?php the_title(); ?>" />
<?php } ?>
<h3><?php the_title(); ?></h3>
<div class="quantity-box">
<button type="button" class="minus">-</button>
<input type="number" class="input-text qty text" step="1" min="1" value="1" />
<button type="button" class="plus">+</button>
</div>
<a href="<?php echo esc_url( $product->add_to_cart_url() ); ?>" class="add-to-cart button">
<?php echo esc_html( $product->add_to_cart_text() ); // Button "Add to cart" ?>
</a>
</div>
<?php
}
echo '</div>';
wp_reset_postdata();
}
}
}
I’ve done so many things, even tried searching stackoverflow.