Support » Developing with WordPress » How to store javascript externally when it utilises php variables?

  • Hi,

    I have been developing a custom extension for my theme over the last few weeks.

    This is my first time “developing” with WordPress. All works fine and I am happy with the resulting functionality, albeit it needs some tidying.

    I am nervous to make it live as I have some concerns whether the code presents some security issues and major inefficiencies in it’s structure.

    I will break down the specific questions using code snippets:

    The form is contained within a modal (for clarity):

    main-block.php

    
    $custom1 = $custom_meta['custom1'];
    
    <form name="customForm">
                    Validation Code:<br>
                    <!-- <input type="number" name="inputcode"><br> -->
                    <input type="password" name="inputcode" id="inputcode" maxlength="6" inputmode="numeric">
                    <input type="text" name="message" id="message" style="display:none; background-color: #FFCCCC;"><br>
                    <input type="button" name="submitbutton" value="Submit" onClick="customfunction()">
                    <div id="errors"></div>
                    </form>
    **Question 1**
    <script type="text/javascript">
    
    **Question 2**
    var i = 0
    
                        var myDots = "<?php echo $custom1 ?>";
                        var dots = $('.points')
                        for (var i = 0; i < myDots; i++) {
                            dots.eq(i).addClass('points-on')
                        }
    
    **Question 3**
    function customfunction() {
                            const userInput = document.customForm.inputcode.value;
                            const pid = "<?php echo $postid ?>";
                            const userid = "<?php echo $userid ?>";
                            fetch(<code>http://...../wp-json/api/v1/customfunction?code=${userInput}&pid=${pid}&userid=${userid}</code>).then(r => r.json()).then(data => {
                                if (data.Data.message === "Correct") {
                                    //Close the modal automatically if the code is correct
                                    document.querySelector(".close-button").click();
                                    //Increase points by one
                                    var points = $(".points")
                                    for (var i = 0; i < data.Data.dots; i++) {
                                        points.eq(i).addClass('points-on')
                                        $('#points').text($(".points-on").length)
                                    }
                                    window.location.reload();
                                } else if (data.Data.message !== "Correct") {
                                    //Unhide the message form field which will display the incorrect message
                                    document.getElementById("message").style.display = 'block';
                                }
                                //Empty the code input box
                                document.customForm.inputcode.value = ""
                                document.customForm.message.value = data.Data.message
                            })
                        };
    </script>

    **Question 1:**

    I really dislike having this javascript declared inline. You can see all the code in the page source and don’t feel like this is normal or best practice. I have tried so many different ways of storing it separately but cannot get it to work. I would prefer it to be stored in child theme’s custom.js file but after adding this to my child functions.php, the functions still do not run:

    add_action('wp_footer', function () {
    	wp_enqueue_script('custom', get_stylesheet_directory_uri() . '/custom.js', array('jquery'), '1.0', true);
    });

    I think perhaps it is because of a mixture of question 2 and question 3? Would love someone to walk me through this.

    **Question 2:**

    This code just sits there and works as needed when called in-line, but in an external javascript file (custom.js), how would main-block.php know how to use it as it is not wrapped in any kind of function. Is this normal? Perhaps this will work itself out if I get help with question 2.

    **Question 3:**

    As the customfunction() uses inline php code to build variables, I feel this could be the reason the external custom.js will not work properly?

        const pid = "<?php echo $postid ?>";
        const userid = "<?php echo $userid ?>";

    How would custom.js create these variables to send to the API?

    The API compares the value of inputcode from the form and performs an add/update_user_meta process based on whether inputcode matches a value in the database stored against the post.

    **TLDR**

    – How can I achieve using an external js file without losing functionality?
    – Are there any security issues with the existing code if no alternatives are available?
    – Is this just awful and I should start again using “x” methods?

    Thank you if you got this far.

Viewing 7 replies - 1 through 7 (of 7 total)
  • Is this just awful and I should start again using โ€œxโ€ methods?

    Yes and yes.
    Don’t put the logic into the client side. Write that logic in PHP and only put as few details as needed into the page for JS to use. The JS should authenticate with the server before making any adds or updates. Use nonces to make sure the user is who they said they were, and is only accessing the thing that was loaded into the page. (don’t delete post 10 when only post 5 was loaded)
    https://developer.wordpress.org/reference/functions/wp_nonce_field/

    If you need JS, make it as generic as possible. Use wp_localize_script to pass variables from PHP to JS.
    https://developer.wordpress.org/reference/functions/wp_localize_script/

    Thanks for responding Joy.

    This is what I have come up with so far in the meantime:

    child functions.php:

    add_action('wp_head', function () {
    // Register the script
    wp_register_script( 'custom_script', get_stylesheet_directory_uri() . '/custom.js' );
    
    // Localize the script with new data
    $custom_api_vars = array(
        'pid' => get_the_id(),
        'uid' => get_current_user()
    );
    wp_localize_script( 'custom_script', 'custom_vars', $custom_api_vars );
    
    // Enqueued script with localized data.
    wp_enqueue_script( 'custom_script' , array('jquery'), '1.0', true);
    
    });

    custom.js:

    function redeem() {
        const pidR = custom_vars.pid;
        const useridR = custom_vars.uid;
        fetch(<code>http://....../wp-json/api/v1/customquery?code=${userInput}&pid=${pidR}&userid=${useridR}</code>).then(r => r.json()).then(data => {
            .....do stuff.....
        })
    };

    Unfortunately I am getting this error in console:

    Uncaught (in promise) ReferenceError: JQuery is not defined

    Am I on the right track?

    I am confused how to perform the add/update_user_meta within my php as I cannot get the result back into php, which is why it is included within the function.

    html/php -> collect inputcode from form
    js -> pull the correct code from the database for that post and check against inputcode. If correct then add/update user meta.

    All this happens in AJAX. Without getting the result back into php, how can I perform the add/update user meta within my php?

    I have never looked into nonce but will do so now.

    If your script needs jQuery, you need to put that in the dependency parameter, and know that the $ variable is not defined because jQuery is loaded in no-conflict mode. Also, isn’t JS case sensitive? It’s jQuery, not JQuery.

    It looks like you have written a custom REST route, so I’m not sure I understand what you mean by “I am confused how to perform the add/update_user_meta within my php”.

    You have not shown any code that is using AJAX.
    Maybe it would make more sense to you to create a form and make it work with no JS. When that is working, you can enhance it with JS. That will help you to mentally separate which piece does what.

    Oh, and your script enqueue stuff isn’t quite right either. But if you write it all without JS, you can wait to fix that.
    (Use the ‘wp_enqueue_scripts’ action instead of ‘wp_head’. And no need to register the script. Just enqueue it and then localize it.)

    Simply changing JQuery to jQuery made it all come alive!

    Thank you so much for your fresh pair of eyes.

    Now to look into your comment around:

    “Donโ€™t put the logic into the client side. Write that logic in PHP and only put as few details as needed into the page for JS to use. The JS should authenticate with the server before making any adds or updates. Use nonces to make sure the user is who they said they were, and is only accessing the thing that was loaded into the page.”

    ….I may be back, but thank you!

    Andrew Nevins

    (@anevins)

    WCLDN 2018 Contributor | Volunteer support

    I’m going to throw this in and walk away because your questions sound difficult, but you can always add PHP into the DOM via a ‘data’ attribute on an element, and then get that with jQuery.

    Thanks for taking the time to respond. As with most things, a leg up and a lot of reading will usually solve the problem ๐Ÿ™‚

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘How to store javascript externally when it utilises php variables?’ is closed to new replies.