admin管理员组

文章数量:1321253

I have a custom plugin that uses shortcodes to generate tables which are meant to be manipulated by the user. As they change the number of servings in A2, it will divide the values in B2-E2 by the value in A2.

The shortcode and table functions correctly the first time it appears on the page. If I try to use the shortcode again, it will generate the table but nothing happens when the value in cell A2 is changed, it doesn't divide the values like it's supposed to.

Any ideas?

Here is my .js code:

    'use strict';

    var updateNutritionValues = function updateNutritionValues(multipler, macros) {
      var carbs = document.querySelector('.nutrition-table__content--carbs');
      var protein = document.querySelector('.nutrition-table__content--protein');
      var fat = document.querySelector('.nutrition-table__content--fat');
      var calories = document.querySelector('.nutrition-table__content--calories');

      carbs.textContent = (macros.carbs / parseInt(multipler)).toFixed(1) + 'g';
      protein.textContent = (macros.protein / parseInt(multipler)).toFixed(1) + 'g';
      fat.textContent = (macros.fat / parseInt(multipler)).toFixed(1) + 'g';
      calories.textContent = (macros.calories / parseInt(multipler)).toFixed(0) + ' cals';
      console.log('carbs => ', (macros.carbs / parseInt(multipler)).toFixed(1) + 'g');
      console.log('carbs => ', (macros.protein / parseInt(multipler)).toFixed(1) + 'g');
      console.log('carbs => ', (macros.fat / parseInt(multipler)).toFixed(1) + 'g');
      console.log('carbs => ', (macros.calories / parseInt(multipler)) + ' cals');
    };

    var nutritionTable = function nutritionTable() {
      var number = document.querySelector('.nutrition-table__number');
      var originalValues = {
        carbs: parseInt(document.querySelector('.nutrition-table__content--carbs').textContent),
        protein: parseInt(document.querySelector('.nutrition-table__content--protein').textContent),
        fat: parseInt(document.querySelector('.nutrition-table__content--fat').textContent),
        calories: parseInt(document.querySelector('.nutrition-table__content--calories').textContent)
      };

      number.addEventListener('change', function (e) {
        updateNutritionValues(parseInt(e.target.value), originalValues);
      });
    };

    document.addEventListener('DOMContentLoaded', function () {
      return nutritionTable();
    });

Here is my .php code

    function ls_nutritional_table_resources() {
        global $post;
        if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'nutrition_table') ) {
            wp_register_style( 'ls-nutritional-table-css',  plugin_dir_url( __FILE__ ) . 'nutritional-table.css' );
            wp_enqueue_style( 'ls-nutritional-table-css' );

            wp_enqueue_script('ls-nutritional-table-js', plugin_dir_url( __FILE__ ) . 'nutritional-table.js' );
        }
    }

    add_action( 'wp_enqueue_scripts', 'ls_nutritional_table_resources');


    add_shortcode('nutrition_table', 'ls_nutritional_table');

    function ls_shortcodes() {
        function ls_nutritional_table($atts) {
            $attributes = shortcode_atts(array(
                'servings' => '1',
                'carbs' => '100',
                'protein' => '400',
                'fats' => '90',
                'calories'=> '2810'
            ), $atts);

            $output = '<div class="nutrition-table">
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Servings</div>
            <div class="nutrition-table__content">
                <input type="number" value="' . esc_attr($attributes['servings']) .  '" min="1" autocomplete="off" class="nutrition-table__number">
            </div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Carbs</div>
            <div class="nutrition-table__content nutrition-table__content--carbs">' . esc_attr($attributes['carbs']) .  'g</div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Protein</div>
            <div class="nutrition-table__content nutrition-table__content--protein">' . esc_attr($attributes['protein']) .  'g</div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Fat</div>
            <div class="nutrition-table__content nutrition-table__content--fat">' . esc_attr($attributes['fats']) .  'g</div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Calories</div>
            <div class="nutrition-table__content nutrition-table__content--calories">' . esc_attr($attributes['calories']) .  ' cals</div>
            </div>
        </div>';

      return $output;
        }
    }

    add_action('init', 'ls_shortcodes');

    /** Always end your PHP files with this closing tag */
    ?>

I have a custom plugin that uses shortcodes to generate tables which are meant to be manipulated by the user. As they change the number of servings in A2, it will divide the values in B2-E2 by the value in A2.

The shortcode and table functions correctly the first time it appears on the page. If I try to use the shortcode again, it will generate the table but nothing happens when the value in cell A2 is changed, it doesn't divide the values like it's supposed to.

Any ideas?

Here is my .js code:

    'use strict';

    var updateNutritionValues = function updateNutritionValues(multipler, macros) {
      var carbs = document.querySelector('.nutrition-table__content--carbs');
      var protein = document.querySelector('.nutrition-table__content--protein');
      var fat = document.querySelector('.nutrition-table__content--fat');
      var calories = document.querySelector('.nutrition-table__content--calories');

      carbs.textContent = (macros.carbs / parseInt(multipler)).toFixed(1) + 'g';
      protein.textContent = (macros.protein / parseInt(multipler)).toFixed(1) + 'g';
      fat.textContent = (macros.fat / parseInt(multipler)).toFixed(1) + 'g';
      calories.textContent = (macros.calories / parseInt(multipler)).toFixed(0) + ' cals';
      console.log('carbs => ', (macros.carbs / parseInt(multipler)).toFixed(1) + 'g');
      console.log('carbs => ', (macros.protein / parseInt(multipler)).toFixed(1) + 'g');
      console.log('carbs => ', (macros.fat / parseInt(multipler)).toFixed(1) + 'g');
      console.log('carbs => ', (macros.calories / parseInt(multipler)) + ' cals');
    };

    var nutritionTable = function nutritionTable() {
      var number = document.querySelector('.nutrition-table__number');
      var originalValues = {
        carbs: parseInt(document.querySelector('.nutrition-table__content--carbs').textContent),
        protein: parseInt(document.querySelector('.nutrition-table__content--protein').textContent),
        fat: parseInt(document.querySelector('.nutrition-table__content--fat').textContent),
        calories: parseInt(document.querySelector('.nutrition-table__content--calories').textContent)
      };

      number.addEventListener('change', function (e) {
        updateNutritionValues(parseInt(e.target.value), originalValues);
      });
    };

    document.addEventListener('DOMContentLoaded', function () {
      return nutritionTable();
    });

Here is my .php code

    function ls_nutritional_table_resources() {
        global $post;
        if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'nutrition_table') ) {
            wp_register_style( 'ls-nutritional-table-css',  plugin_dir_url( __FILE__ ) . 'nutritional-table.css' );
            wp_enqueue_style( 'ls-nutritional-table-css' );

            wp_enqueue_script('ls-nutritional-table-js', plugin_dir_url( __FILE__ ) . 'nutritional-table.js' );
        }
    }

    add_action( 'wp_enqueue_scripts', 'ls_nutritional_table_resources');


    add_shortcode('nutrition_table', 'ls_nutritional_table');

    function ls_shortcodes() {
        function ls_nutritional_table($atts) {
            $attributes = shortcode_atts(array(
                'servings' => '1',
                'carbs' => '100',
                'protein' => '400',
                'fats' => '90',
                'calories'=> '2810'
            ), $atts);

            $output = '<div class="nutrition-table">
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Servings</div>
            <div class="nutrition-table__content">
                <input type="number" value="' . esc_attr($attributes['servings']) .  '" min="1" autocomplete="off" class="nutrition-table__number">
            </div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Carbs</div>
            <div class="nutrition-table__content nutrition-table__content--carbs">' . esc_attr($attributes['carbs']) .  'g</div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Protein</div>
            <div class="nutrition-table__content nutrition-table__content--protein">' . esc_attr($attributes['protein']) .  'g</div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Fat</div>
            <div class="nutrition-table__content nutrition-table__content--fat">' . esc_attr($attributes['fats']) .  'g</div>
            </div>
            <div class="nutrition-table__column">
            <div class="nutrition-table__head">Calories</div>
            <div class="nutrition-table__content nutrition-table__content--calories">' . esc_attr($attributes['calories']) .  ' cals</div>
            </div>
        </div>';

      return $output;
        }
    }

    add_action('init', 'ls_shortcodes');

    /** Always end your PHP files with this closing tag */
    ?>
Share Improve this question asked Sep 28, 2020 at 6:27 jmc1885jmc1885 31 bronze badge
Add a comment  | 

1 Answer 1

Reset to default 0

The reason your code only applies to the first table, is because you are only selecting the first input with var number = document.querySelector('.nutrition-table__number');

You need to loop over all your tables, and add an event listener to each.

Here is an example of how this could work. The plugin pattern is from https://vanillajstoolkit/boilerplates/revealing-module-pattern/

/*!
 * Revealing Constructor Pattern Boilerplate
 * (c) 2019 Chris Ferdinandi, MIT License, https://gomakethings
 */
var NutritionTablesPlugin = (function () {

    'use strict';

    /**
     * Create the Constructor object
     */
    var Constructor = function (selector) {

        //
        // Variables
        //

        var publicAPIs = {};

        var nodes = document.querySelectorAll(selector);

        //
        // Methods
        //
        var allNodes = function (callback) {
            for (var i = 0; i < nodes.length; i++) {
                callback(nodes[i], i);
            }
        };

        /**
         * A private method
         */
        var updateNutritionValues = function (table, multipler, macros) {
            var carbs = table.querySelector( '.nutrition-table__content--carbs');
            var protein = table.querySelector('.nutrition-table__content--protein');
            var fat = table.querySelector('.nutrition-table__content--fat');
            var calories = table.querySelector('.nutrition-table__content--calories');

            carbs.textContent = (macros.carbs / parseInt(multipler)).toFixed(1) + 'g';
            protein.textContent = (macros.protein / parseInt(multipler)).toFixed(1) + 'g';
            fat.textContent = (macros.fat / parseInt(multipler)).toFixed(1) + 'g';
            calories.textContent = (macros.calories / parseInt(multipler)).toFixed(0) + ' cals';
        };


        /**
         * Another public method
         */
        publicAPIs.init = function (options) {
            allNodes( function(node){

                var originalValues = {
                    carbs: parseInt(node.querySelector('.nutrition-table__content--carbs').textContent),
                    protein: parseInt(node.querySelector('.nutrition-table__content--protein').textContent),
                    fat: parseInt(node.querySelector('.nutrition-table__content--fat').textContent),
                    calories: parseInt(node.querySelector( '.nutrition-table__content--calories').textContent)
                };

                node.addEventListener('change', function (e) {
                    updateNutritionValues(node, parseInt(e.target.value), originalValues);
                });
            });
        };

        //
        // Return the Public APIs
        //
        return publicAPIs;
    };

    //
    // Return the Constructor
    //
    return Constructor;

})();

document.addEventListener("DOMContentLoaded", function(event) {
    var nutrition = new NutritionTablesPlugin('.nutrition-table');
    nutrition.init();

});

And in your PHP code, you'll want to use esc_html for the carbs/fat/protein/calories attributes output. https://developer.wordpress/reference/functions/esc_html/

本文标签: phpWhy does my custom plugin only function correctly once per page