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_' )
)文档可在此处找到:
- https://developer.wordpress.org/plugins/javascript/ajax/
- https://developer.wordpress.org/reference/hooks/wp_ajax_action/
- https://developer.wordpress.org/reference/hooks/wp_ajax_nopriv__requestaction/
WordPress JSON 响应 wp_send_json_error()
和 wp_send_json_success()
:
- https://developer.wordpress.org/reference/functions/wp_send_json_error/
- https://developer.wordpress.org/reference/functions/wp_send_json_success/
在前端加载 javascript:
我是 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_' )
)文档可在此处找到:
- https://developer.wordpress.org/plugins/javascript/ajax/
- https://developer.wordpress.org/reference/hooks/wp_ajax_action/
- https://developer.wordpress.org/reference/hooks/wp_ajax_nopriv__requestaction/
WordPress JSON 响应 wp_send_json_error()
和 wp_send_json_success()
:
- https://developer.wordpress.org/reference/functions/wp_send_json_error/
- https://developer.wordpress.org/reference/functions/wp_send_json_success/
在前端加载 javascript: