Quantity field doesn’t work in a custom plugin for WooCommerce and Elementor

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

  1. custom-product-widget.php
  2. script.js
  3. style.css
  4. 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.