Uncaught SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse - Wordpress

Uncaught SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse - Wordpress

我是 AJAX 的新手,看来我可能遗漏了一个非常基本的细节。如果我在不使用 Wordpress 的情况下在本地执行此操作,它会正常工作。我向您发送 link:

但是如果我用 Wordpress 创建一个函数,它会出现:

Uncaught SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse

这是我的代码:

add_action( 'wp_head', 'conta_visite');
function conta_visite(){
    
    $dir = get_stylesheet_directory() . "/users";
    if (!file_exists($dir)) {
    wp_mkdir_p( $dir );
        
}
if(isset($_POST['getCustomerCount']))
{

    $dbfile = get_stylesheet_directory() . "/visitors.db"; // path to data file
    $expire = 3; // average time in seconds to consider someone online before removing from the list
    if(!file_exists($dbfile)) {
        echo json_encode(['success'=> false,'error_message'=>"Error: Data file " . $dbfile . " NOT FOUND!"]);
        die();
        //die("Error: Data file " . $dbfile . " NOT FOUND!");
    }

    if(!is_writable($dbfile)) {
        echo json_encode(['success'=> false,'error_message'=>"Error: Data file " . $dbfile . " is NOT writable! Please CHMOD it to 666!"]);
        die();
        //die("Error: Data file " . $dbfile . " is NOT writable! Please CHMOD it to 666!");
    }

    $count = CountVisitors($dbfile, $expire);
    if(is_numeric($count)){
        $out = $count; // format the result to display 3 digits with leading 0's
        echo json_encode(['success'=>'true', 'customer_count'=>$out]);
    }
    else 
    {
        echo json_encode(['success'=> false, 'error_message'=>"count is not numeric"]);
    }
}
else{
    echo $dbfile;
    echo json_encode($_POST);
}


function CountVisitors() {
    global $dbfile, $expire;
    $cur_ip = getIP();
    $cur_time = time();
    $dbary_new = array();

  $dbary = json_decode(file_get_contents($dbfile),true);
    if(is_array($dbary)) {
      
      foreach($dbary as $user_ip => $user_time){
        if(($user_ip != $cur_ip) && (($user_time + $expire) > $cur_time)) {
                $dbary_new[$user_ip] = $user_time;
            }
      }
    }
  
    $dbary_new[$cur_ip] = $cur_time; // add record for current user

    $fp = fopen($dbfile, "w");
    fputs($fp, json_encode($dbary_new));
    fclose($fp);

    return count($dbary_new);
}

function getIP() {
    if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    elseif(isset($_SERVER['REMOTE_ADDR'])) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    else
    {
        $ip = "0.0.0.0";
    }
    return $ip;
}

    
?>

<p id="customer_count">Customers Online: <span></span></p>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
        function updateCustomerCount() {
  $.ajax({
    type: "POST",
    cache: false,
    data: {getCustomerCount: true},

        success: function(response) {

            var data = JSON.parse(response);
            //var data = response;
            console.log(response);
            if (data.success) {
                $("#customer_count span").text(data.customer_count);
            } else {
                console.log(data.error_message);
            }

        },
        error: function(response, request, status, error) {
            console.log(error);
        }
    });
setTimeout(updateCustomerCount, 2000);
} 
updateCustomerCount();
        
</script>

<?php
}

这是 Wordpress 中的演示 link: 您可以在 header.

的右上角找到计数器

你能帮帮我吗?因为我快疯了,我不知道我哪里错了....

好的,这应该可以满足您的需求。我已经重写了您的代码以更好地集成 WordPress。

首先,您需要创建一个新的 javascript 文件名 visitor-counter.js 并将其放置在主题目录中的 js 文件夹中。这将用于我们的 jQuery 和 ajax 请求。

/js/visitor-counter.js

(function($) {

    window.VisitorCounter = window?.VisitorCounter || {

        /**
         * @type {object} Temp storage object
         */
        _temp: {},

        /**
         * Get a PHP variable.
         *
         * @param varName
         * @returns {*}
         */
        getVar(varName) {
            const vars = window?.VisitorCounterVars;
            return vars?.[varName];
        },

        /**
         * Make ajax request to server, store response in temp object.
         *
         * @returns {Promise<unknown>}
         */
        request() {
            return new Promise((accept, reject) => {
                const url = this.getVar('ajaxUrl');
                const action = this.getVar('ajaxAction');
                const post_id = this.getVar('post_id');

                if (url && action) {
                    $.ajax({
                        url: url,
                        data: {
                            action: action,
                            post_id: post_id
                        },
                        cache: false
                    }).then(response => {
                        this._temp.count = response.data;
                        accept(response);
                        console.log(response);
                    });
                } else {
                    reject('Visitor counter ajax url or action not available.');
                }
            });
        },

        /**
         * Get the count value.
         *
         * @returns {number}
         */
        getCount() {
            return parseInt(this._temp?.count || 0);
        },

        /**
         * Refresh data continuously.
         *
         * @param {callback} callback
         * @param {number} timeout
         */
        refresh(callback, timeout) {
            this._temp.lastRefreshed = Date.now();

            this.request().then(() => {
                const now = Date.now();

                callback.apply(this);

                const timeoutDiff = now - this._temp.lastRefreshed;

                // If request took longer than timeout, run next refresh instantly.
                if (timeout && timeoutDiff >= timeout) {
                    this.refresh(callback, timeout);
                }

                // Request was quicker than timeout, queue next refresh call.
                else {
                    setTimeout(() => {
                        this.refresh(callback, timeout);
                    }, timeout - timeoutDiff);
                }
            });
        }
    };

    // Initiate refresh loop
    VisitorCounter.refresh(function() {
        $('#customer_count span').text(VisitorCounter.getCount());
    }, 2000);

})(jQuery);

接下来将以下内容添加到您的主题 functions.php 文件中...

/functions.php

class VisitorCounter {
        
    private static $instance;

    /**
     * @var string $file Relative path to the tracking file.
     */

    public $file = 'users/';

    /**
     * @var int $expires Automatically expire vistor after X amount of seconds.
     */
    
    public $expires = 3;

    /**
     * @return $this
     */
    public static function init() {
        if ( !static::$instance ) {
            static::$instance = new static( ...func_get_args() );
        }

        return static::$instance;
    }

    /**
     * Get the full database file path and create file if not exists.
     *
     * @return string|false
     */
    public function getPath() {

        $post_id = $_GET['post_id'];
        $path = get_stylesheet_directory() . '/' . ltrim( $this->file, '/' ) . 'product-view-id-' . $post_id . '.db';
        $exists = file_exists( $path );

        if ( !$exists ) {
            wp_mkdir_p( dirname( $path ) );
            $exists = touch( $path );
        }
        return $exists ? $path : true;
    }
    /**
     * Read the contents of the visitors database file as a JSON.
     *
     * @return array
     */
    public function getData() {
        if ( $path = $this->getPath() ) {
            if ( $contents = file_get_contents( $path ) ) {
                if ( $json = @json_decode( $contents, true ) ) {
                    return $this->cleanData( $json );
                }
            }
        }

        return [];
    }

    /**
     * Clean the visitor data by removing expired entries.
     *
     * @param array $input
     * @return array
     */
    private function cleanData( array $input ) {
        $now = time();

        foreach ( $input as $ip => $timestamp ) {
            if ( $timestamp + $this->expires < $now ) {
                unset( $input[ $ip ] );
            }
        }

        return $input;
    }

    /**
     * Add visitor count data.
     *
     * @param string $ip
     * @param int $timestamp
     * @return array
     */
    public function logUser() {
        
        // Get current data.
        $data = $this->getData();

        // Add new entry.
        if ( $ip = $this->getUserIp() ) {
            $data[ $ip ] = time();
        }

        // Clean data before saving.
        $data = $this->cleanData( $data );

        // Encode and save data.
        file_put_contents( $this->getPath(), wp_json_encode( $data ) );

        // Return data.
        return $data;
    }

    /**
     * Get the current users IP address.
     *
     * @return string|null
     */
    public function getUserIp() {

        // In order of preference, with the best ones for this purpose first.
        $address_headers = [
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR'
        ];

        $client_ip = null;

        foreach ( $address_headers as $header ) {
            if ( !empty( $_SERVER[ $header ] ) ) {
                /*
                 * HTTP_X_FORWARDED_FOR can contain a chain of comma-separated
                 * addresses. The first one is the original client. It can't be
                 * trusted for authenticity, but we don't need to for this purpose.
                 */
                $address_chain = explode( ',', $_SERVER[ $header ] );
                $client_ip = trim( $address_chain[ 0 ] );
                break;
            }
        }

        return $client_ip;
    }
}

/**
 * Helper function for visitor counter class.
 *
 * @return VisitorCounter
 */
function visitor_counter() {
    return VisitorCounter::init();
}


/**
 * Register an ajax request handler.
 */
add_action( 'wp_ajax_active_visitor', 'handle_visitor_activity' );
add_action( 'wp_ajax_nopriv_active_visitor', 'handle_visitor_activity' );
function handle_visitor_activity() {
    $controller = visitor_counter();
    $controller->logUser();
    wp_send_json_success( count( $controller->getData() ) );
}


/**
 * Load our javascript file on the frontend data.
 */
add_action( 'wp_enqueue_scripts', function() {
if ( is_product()) {
    // Load the counter javascript file after `jquery` in the footer.
    wp_enqueue_script( 'visitor-counter', get_stylesheet_directory_uri() . '/js/visitor-counter.js', [ 'jquery' ], '1.0.0', true );

    // Load php data that can be accessed in javascript.
    wp_localize_script( 'visitor-counter', 'VisitorCounterVars', [
        'ajaxUrl' => admin_url( 'admin-ajax.php' ),
        'ajaxAction' => 'active_visitor',
        'post_id'=> get_the_id()
    ] );
}
} );

要查找的内容...

WordPress ajax 处理程序(add_action( 'wp_ajax_' )add_action( 'wp_ajax_nopriv_' ))文档可在此处找到:

WordPress JSON 响应 wp_send_json_error()wp_send_json_success()

在前端加载 javascript: