admin管理员组

文章数量:1122792

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 ?

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");                        
                       }
                   })
          });
        });
    }
})();

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);
              });

          });
        };
    })();

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 ?

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");                        
                       }
                   })
          });
        });
    }
})();

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);
              });

          });
        };
    })();
Share Improve this question edited May 19, 2024 at 1:30 pbee asked May 14, 2024 at 7:34 pbeepbee 52 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 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.

本文标签: phpCalling a function via a shortcode in javascript