0

I'm looking to dynamically change the page-comments option based on whether the user clicks a URL. I have two functions to do this:


function psb_comment_listener_func(){
    echo "
    <script>
    function myFunction(event) {
        event.preventDefault();
        console.log('in my function');
        '<?php echo do_shortcode(\"[psb_all_comments]\"); ?>';
        }
    console.log('in the listener');
    document.getElementsByClassName('nav-previous')[0].onclick = function() {myFunction(event)};
    </script>
    ";
    }
add_filter( 'learn-press/after-content-item-summary/lp_lesson', 'psb_comment_listener_func');


function psb_all_comments_func(){
    echo "
    <script>
    console.log('in the shortcode');
    </script> ";
    update_option('page_comments', false);
    }
add_shortcode( 'psb_all_comments', 'psb_all_comments_func');    
   

The plan is that the listener catches the onclick and the function then stops the hyperlink from happening and calls the shortcode to update_option for page_comments. I have two problems:

Problem 1: If I copy and paste the javascript

function myFunction(event) {
        event.preventDefault();
        console.log('in my function');
        '<?php echo do_shortcode(\"[psb_all_comments]\"); ?>';
        }
    console.log('in the listener');
    document.getElementsByClassName('nav-previous')[0].onclick = function() {myFunction(event)}; 

into the browser console and press enter. The "in the listener" message appears (this is good) when the link ('older comments') is clicked the "in my function" appears (this is also good). But the call to the other function via the shortcode doesnt happen. There is no "in the shortcode" message. What am I missing here ?

enter image description here

Problem 2: None of it works when called from within the PHP function file. It only works in the browser console. Again, what am I missing ? Thanks Paul.


This is where I'm at now

PHP code

function psb_register_script() { 
    wp_register_script(
        'psb_navprev', 
        plugin_dir_url( __FILE__ ).'/js/psb_navprev.js',
        array(),
        wp_get_theme()->get( 'Version' ),
        array(
            'strategy' => 'defer',
            'in_footer' => true,
        )
    );
}


function psb_enqueue_script() {
    //if ( is_singular( 'lp_course' ) ) {
        wp_enqueue_script( 'psb_navprev', plugin_dir_url( __FILE__ ).'/js/psb_navprev.js',array('jquery'), '1.0', true );

        //localize script
        wp_localize_script( 'psb_navprev', 'psb_object', 
        array( 
            'ajax_url' => admin_url( 'admin-ajax.php' ),
            'nonce' => wp_create_nonce('psb-nonce'),
             )
         );
    //}
}

//register and enqueue script
add_action( 'wp_enqueue_scripts', 'psb_register_script' );
add_action( 'template_redirect', 'psb_enqueue_script' );

add_action( 'wp_ajax_nopriv_psb_comment_cmd', 'psb_comment_cmd' );
add_action( 'wp_ajax_psb_comment_cmd', 'psb_comment_cmd' );


function psb_comment_cmd(){
  echo " <script> console.log('in the handler'); </script> ";
  check_ajax_referer( 'psb-nonce', 'nonce' );  // Check the nonce.    

 if (isset($_POST['psb_comment_cmd'])) {
       //psb_all_comments()
        echo " <script> console.log('comment => all'); </script> ";
        wp_die();                               // clean up
          }
    }                          


function psb_all_comments_func(){
    echo "
    <script>
    console.log('in the update function');
    </script> ";
    update_option('page_comments', false);
    }
// clicky-script.js

(function(){
    const navPrevElement = document.querySelector('.nav-previous');
    if (navPrevElement) {
        navPrevElement.addEventListener('click', function(event){
            console.log('in the clicky script');
            event.preventDefault();

            jQuery(document).ready(function($) {            
                    $.ajax({
                        url:psb_object.ajax_url, 
                        type: "post",
                        contentType: "json",
                        dataType: "json",
                        data: {action: "psb_comment_cmd"},
                        success: function(msg) {        
                          console.log("AJAX success");                    
                        },
                        error: function() {
                          console.log("AJAX fail");                        
                       }
                   })
          });
        });
    }
})();

console log

Final resolution :-)

PHP

add_action ('rest_api_init', function() {
    register_rest_route('psb/v1', 'posts', [
        'methods' => 'GET',
        'callback' => 'psb_posts',
        ]);
});


function psb_posts() {
    update_option('page_comments', false);
    return 'in the posts callback';
}


Javascript

// clicky-script.js


(function(){
        const navPrevElement = document.querySelector('.nav-previous');
        if (navPrevElement) {
        navPrevElement.addEventListener('click', function(event){
            console.log('in the clicky script');
            event.preventDefault();

            const apiUrl = window.location.origin + '/wp-json/psb/v1/posts';
            fetch(apiUrl)
              .then(response => {
                if (!response.ok) {
                  throw new Error('Network response was not ok');
                }
                return response.json();
              })
              .then(data => {
                console.log(data);     // set comment count 
                location.reload();     // refresh the page
              })
              .catch(error => {
                console.error('API Error:', error);
              });

          });
        };
    })();

1 Answer 1

1

I'm afraid the code you've shared is rather wonky and there isn't just one thing that is backwards. Here are the first few things that came into my mind.

add_filter( 'learn-press/after-content-item-summary/lp_lesson', 'psb_comment_listener_func');

When you attach a callback function to a filter with add_filter, the callback should return a value. If the callback isn't supposed to return anything, but for example print something on the screen, then you should generally use add_action to hook the callback to an action. echoing inside a filter may cause unexpected results as the printed content may not appear in the intended place.

function psb_all_comments_func() {...}

The shortcode callback is also supposed to return a string and not echo anything. As noted on the Shortcode API Codex page, "..anything that is echoed will be output to the browser, but it won't appear in the correct place on the page..".

Another problematic thing is calling update_option() inside the shortcode callback. The option is updated every time the shortcode is evaluated and executed whether the user clicked anything or not.

As there isn't any additional details about the option, I assume it is a global option with a single boolean value. Based on this assumption update_option() poses another issue. Unless there is other code, or manual admin intervention, to toggle the option back to true, then its value is set to false for everyone until the end of time when the shortcode is executed the first time.

myFunction(event) {...}

When copying and pasting the script to the browser console '<?php echo do_shortcode(\"[psb_all_comments]\"); ?>'; is evaluated as a plain string, not PHP, and that is why it doesn't do anything. PHP is a server side language and you can't execute it with javascript on the frontend.

What to do instead?

I recommend splitting the code into smaller parts by the different responsibilities. Something along these lines,

  • A separate script file to house the js clicky thing
  • A PHP function to register the script file for later when needed
  • A custom WP REST API endpoint and a controller (or admin-ajax.php handler, if you're not into WP REST API) for receiving js requests and toggling settings in the backend
  • A callback attached to suitable action for determining, if the script file should be enqueued or not

The script file.

// clicky-script.js
(function(){
    const navPrevElement = document.querySelector('.nav-previous');

    if (navPrevElement) {
        navPrevElement.addEventListener('click', function(event){
            // do something e.g.
            // hide element with js
            // or send ajax request to REST endpoint or admin-ajax.php
        });
    }
})();

The PHP stuff.

// e.g. functions.php
add_action( 'wp_enqueue_scripts', 'wpse_425194_register_script' );
function wpse_425194_register_script() { 
    wp_register_script(
        'wpse_425194_clicky_script', 
        get_template_directory_uri() .'/assets/clicky-script.js',
        array(),
        wp_get_theme()->get( 'Version' ),
        array(
            'strategy' => 'defer',
            'in_footer' => true,
        )
    );
}

add_action( 'template_redirect', 'wpse_425194_enqueue_script' );
function wpse_425194_enqueue_script() {
    if ( is_singular( 'my-post-type' ) ) {
        wp_enqueue_script( 'wpse_425194_clicky_script' );
    }
}

See WP REST API Handbook or Ajax documentation for registering the backend handler.

3
  • Hi Antti, thanks so much for taking the time to point me in the correct direction. Yes using Ajax would be the best solution. I've implemented your suggestion but am stuck with a jquery error 400 (bad request). The post is pointing to the correct admin-ajax.php as far as I can tell and the parameters look fine. The register and enqueue (Im doing this outside of a condition for the moment) in the PHP file look good as far as I can tell but the call fails for some reason. I've posted where I'm at in the question block. Cheers Paul.
    – pbee
    Commented May 17 at 1:24
  • @pbee Thank you for the update. It looks like the nonce value is not passed along the ajax request to the server. That might be causing the issue. Commented May 17 at 20:38
  • Hi Antti, again thanks for your help. I couldn't get the ajax call to go :-( I think the error 400 (Bad Request) is too general to target the actual problem. In the end I took your other suggestion and built and API. This works perfectly. cheers Paul
    – pbee
    Commented May 19 at 1:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.