Start using REST API; story comments
At least for everything that cannot use the fast AJAX, which is still superior.
This commit is contained in:
parent
e68e30fec1
commit
662e78bf5b
@ -218,6 +218,11 @@ if ( ! defined( 'FICTIONEER_STORY_COMMENT_COUNT_TIMEOUT' ) ) {
|
||||
* Booleans
|
||||
*/
|
||||
|
||||
// Prevent warnings
|
||||
if ( ! defined( 'WP_DEBUG' ) ) {
|
||||
define( 'WP_DEBUG', false );
|
||||
}
|
||||
|
||||
// Boolean: Theme cache purging on post update
|
||||
if ( ! defined( 'FICTIONEER_CACHE_PURGE_ASSIST' ) ) {
|
||||
define( 'FICTIONEER_CACHE_PURGE_ASSIST', true );
|
||||
@ -550,28 +555,11 @@ if ( get_option( 'fictioneer_enable_oauth' ) ) {
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_controller.php';
|
||||
|
||||
if ( is_admin() ) {
|
||||
// Required for AJAX
|
||||
require_once __DIR__ . '/includes/functions/comments/_story_comments.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_ajax.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_form.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_threads.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_moderation.php';
|
||||
}
|
||||
|
||||
function fictioneer_conditional_require_comments() {
|
||||
if ( is_singular( 'fcn_story' ) ) {
|
||||
require_once __DIR__ . '/includes/functions/hooks/_story_hooks.php';
|
||||
}
|
||||
|
||||
if ( comments_open() || is_singular( 'fcn_story' ) ) {
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_form.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_threads.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_moderation.php';
|
||||
}
|
||||
}
|
||||
add_action( 'wp', 'fictioneer_conditional_require_comments' );
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_ajax.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_form.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_threads.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_comments_moderation.php';
|
||||
require_once __DIR__ . '/includes/functions/comments/_story_comments.php';
|
||||
|
||||
/**
|
||||
* Add functions for users.
|
||||
|
@ -272,7 +272,7 @@ if ( ! function_exists( 'fictioneer_api_request_story' ) ) {
|
||||
new WP_Error(
|
||||
'invalid_story_id',
|
||||
'No valid story was found matching the ID.',
|
||||
['status' => '400']
|
||||
array( 'status' => '400' )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -554,6 +554,7 @@ function fictioneer_add_custom_scripts() {
|
||||
// Localize application
|
||||
wp_localize_script( 'fictioneer-application-scripts', 'fictioneer_ajax', array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'rest_url' => get_rest_url( null, 'fictioneer/v1/' ),
|
||||
'ttl' => FICTIONEER_AJAX_TTL,
|
||||
'login_ttl' => FICTIONEER_AJAX_LOGIN_TTL,
|
||||
'post_debounce_rate' => FICTIONEER_AJAX_POST_DEBOUNCE_RATE
|
||||
|
@ -508,9 +508,11 @@ if ( ! function_exists( 'fictioneer_validate_id' ) ) {
|
||||
|
||||
function fictioneer_validate_id( $id, $for_type = [] ) {
|
||||
$safe_id = intval( $id );
|
||||
$types = is_array( $for_type ) ? $for_type : [$for_type];
|
||||
$types = is_array( $for_type ) ? $for_type : [ $for_type ];
|
||||
|
||||
if ( empty( $safe_id ) || $safe_id < 0 ) return false;
|
||||
if ( empty( $safe_id ) || $safe_id < 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! empty( $for_type ) && ! in_array( get_post_type( $safe_id ), $types ) ) {
|
||||
return false;
|
||||
|
@ -80,29 +80,80 @@ if ( ! function_exists( 'fictioneer_build_story_comment' ) ) {
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// SEND STORY COMMENTS - AJAX
|
||||
// SEND STORY COMMENTS - REST
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Sends a block of comments for a given story via AJAX
|
||||
* Register REST API endpoint to fetch story comments
|
||||
*
|
||||
* @since Fictioneer 4.0
|
||||
* Endpoint URL: /wp-json/fictioneer/v1/get_story_comments
|
||||
*
|
||||
* Expected Parameters:
|
||||
* - post_id (required): The ID of the story post.
|
||||
* - page (optional): The page number for pagination. Default 1.
|
||||
*
|
||||
* @since Fictioneer 5.6.3
|
||||
*/
|
||||
|
||||
function fictioneer_ajax_request_story_comments() {
|
||||
// Nonce
|
||||
check_ajax_referer( 'fictioneer_nonce', 'nonce' );
|
||||
function fictioneer_register_endpoint_get_story_comments() {
|
||||
register_rest_route(
|
||||
'fictioneer/v1',
|
||||
'/get_story_comments',
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => 'fictioneer_rest_get_story_comments',
|
||||
'args' => array(
|
||||
'post_id' => array(
|
||||
'validate_callback' => function( $param, $request, $key ) {
|
||||
return is_numeric( $param );
|
||||
},
|
||||
'sanitize_callback' => 'absint',
|
||||
'required' => true
|
||||
),
|
||||
'page' => array(
|
||||
'validate_callback' => function( $param, $request, $key ) {
|
||||
return is_numeric( $param );
|
||||
},
|
||||
'sanitize_callback' => 'absint',
|
||||
'default' => 1
|
||||
)
|
||||
),
|
||||
'permission_callback' => '__return_true' // Public
|
||||
)
|
||||
);
|
||||
}
|
||||
add_action( 'rest_api_init', 'fictioneer_register_endpoint_get_story_comments' );
|
||||
|
||||
/**
|
||||
* Sends HTML of paginated comments for a given story
|
||||
*
|
||||
* @since Fictioneer 4.0
|
||||
* @since Fictioneer 5.6.3 Refactored for REST API.
|
||||
*
|
||||
* @param WP_REST_Request $WP_REST_Request Request object.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response or error.
|
||||
*/
|
||||
|
||||
function fictioneer_rest_get_story_comments( WP_REST_Request $request ) {
|
||||
// Validations
|
||||
$story_id = isset( $_GET['post_id'] ) ? fictioneer_validate_id( $_GET['post_id'], 'fcn_story' ) : false;
|
||||
$story_id = $request->get_param( 'post_id' );
|
||||
$story_id = isset( $story_id ) ? fictioneer_validate_id( $_GET['post_id'], 'fcn_story' ) : false;
|
||||
$default_error = array( 'error' => __( 'Comments could not be loaded.', 'fictioneer' ) );
|
||||
|
||||
// Abort if not a story
|
||||
if ( ! $story_id ) {
|
||||
wp_send_json_error( array( 'error' => __( 'Comments could not be loaded.', 'fictioneer' ) ) );
|
||||
if ( WP_DEBUG ) {
|
||||
$data = array( 'error' => __( 'Provided post ID is not a story ID.', 'fictioneer' ) );
|
||||
} else {
|
||||
$data = $default_error;
|
||||
}
|
||||
|
||||
return rest_ensure_response( array( 'data' => $data, 'success' => false ), 400 );
|
||||
}
|
||||
|
||||
// Setup
|
||||
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
|
||||
$page = $request->get_param( 'page' );
|
||||
$story = fictioneer_get_story_data( $story_id, true, array( 'force_comment_count_refresh' => true ) );
|
||||
$chapter_ids = $story['chapter_ids']; // Only contains publicly visible chapters
|
||||
$comments_per_page = get_option( 'comments_per_page' );
|
||||
@ -111,7 +162,13 @@ function fictioneer_ajax_request_story_comments() {
|
||||
|
||||
// Abort if no chapters have been found
|
||||
if ( count( $chapter_ids ) < 1 ) {
|
||||
wp_send_json_error( array( 'error' => __( 'No chapters with comments.', 'fictioneer' ) ) );
|
||||
if ( WP_DEBUG ) {
|
||||
$data = array( 'error' => __( 'There are no valid chapters with comments.', 'fictioneer' ) );
|
||||
} else {
|
||||
$data = $default_error;
|
||||
}
|
||||
|
||||
return rest_ensure_response( array( 'data' => $data, 'success' => false ) );
|
||||
}
|
||||
|
||||
// Collect titles and permalinks of all chapters
|
||||
@ -224,10 +281,11 @@ function fictioneer_ajax_request_story_comments() {
|
||||
// Get buffer
|
||||
$output = fictioneer_minify_html( ob_get_clean() );
|
||||
|
||||
// Response body (compatible to wp_send_json_success())
|
||||
$data = array( 'html' => $output, 'postId' => $story_id, 'page' => $page );
|
||||
|
||||
// Return buffer
|
||||
wp_send_json_success( array( 'html' => $output, 'postId' => $story_id, 'page' => $page ) );
|
||||
return rest_ensure_response( array( 'data' => $data, 'success' => true ) );
|
||||
}
|
||||
add_action( 'wp_ajax_nopriv_fictioneer_ajax_request_story_comments', 'fictioneer_ajax_request_story_comments' );
|
||||
add_action( 'wp_ajax_fictioneer_ajax_request_story_comments', 'fictioneer_ajax_request_story_comments' );
|
||||
|
||||
?>
|
||||
|
2
js/story.min.js
vendored
2
js/story.min.js
vendored
@ -1 +1 @@
|
||||
var fcn_storyCommentPage=1,fcn_storySettings=fcn_getStorySettings();function fcn_getStorySettings(){let t=localStorage.getItem("fcnStorySettings");return t=t&&fcn_isValidJSONString(t)?JSON.parse(t):fcn_defaultStorySettings(),(!t.hasOwnProperty("timestamp")||t.timestamp<1674770712849)&&(t=fcn_defaultStorySettings(),t.timestamp=Date.now()),fcn_setStorySettings(t),t}function fcn_defaultStorySettings(){return{view:"list",order:"asc",timestamp:1674770712849}}function fcn_setStorySettings(t){"object"==typeof t&&(fcn_storySettings=t,localStorage.setItem("fcnStorySettings",JSON.stringify(t)))}function fcn_applyStorySettings(){"object"==typeof fcn_storySettings&&(_$$("[data-view]").forEach((t=>{t.dataset.view="grid"==fcn_storySettings.view?"grid":"list"})),_$$("[data-order]").forEach((t=>{t.dataset.order="desc"==fcn_storySettings.order?"desc":"asc"})))}function fcn_toggleStoryTab(t){_$$(".story__article ._current").forEach((t=>{t.classList.remove("_current")})),_$$$(t.dataset.target).classList.add("_current"),_$$$("tabs").dataset.current=t.dataset.target,t.classList.add("_current")}function fcn_loadStoryComments(){let t;_$(".load-more-list-item").remove(),_$(".comments-loading-placeholder").classList.remove("hidden"),fcn_ajaxGet({action:"fictioneer_ajax_request_story_comments",post_id:fcn_inlineStorage.postId,page:fcn_storyCommentPage}).then((e=>{e.success?(_$(".fictioneer-comments__list > ul").innerHTML+=e.data.html,fcn_storyCommentPage++):e.data?.error&&(t=fcn_buildErrorNotice(e.data.error))})).catch((e=>{t=fcn_buildErrorNotice(e)})).then((()=>{_$(".comments-loading-placeholder").remove(),t&&_$(".fictioneer-comments__list > ul").appendChild(t)}))}fcn_applyStorySettings(),_$$$("button-toggle-chapter-order")?.addEventListener("click",(t=>{fcn_storySettings.order="asc"===t.currentTarget.dataset.order?"desc":"asc",fcn_setStorySettings(fcn_storySettings),fcn_applyStorySettings()})),_$$$("button-toggle-chapter-view")?.addEventListener("click",(t=>{fcn_storySettings.view="list"===t.currentTarget.dataset.view?"grid":"list",fcn_setStorySettings(fcn_storySettings),fcn_applyStorySettings()})),_$$(".chapter-group__folding-toggle").forEach((t=>{t.addEventListener("click",(t=>{const e=t.currentTarget.closest(".chapter-group[data-folded]");e&&(e.dataset.folded="true"==e.dataset.folded?"false":"true")}))})),_$$(".tabs__item").forEach((t=>{t.addEventListener("click",(t=>{fcn_toggleStoryTab(t.currentTarget)}))})),_$(".comment-section")?.addEventListener("click",(t=>{t.target?.classList.contains("load-more-comments-button")&&fcn_loadStoryComments()}));
|
||||
var fcn_storyCommentPage=1,fcn_storySettings=fcn_getStorySettings();function fcn_getStorySettings(){let t=localStorage.getItem("fcnStorySettings");return t=t&&fcn_isValidJSONString(t)?JSON.parse(t):fcn_defaultStorySettings(),(!t.hasOwnProperty("timestamp")||t.timestamp<1674770712849)&&(t=fcn_defaultStorySettings(),t.timestamp=Date.now()),fcn_setStorySettings(t),t}function fcn_defaultStorySettings(){return{view:"list",order:"asc",timestamp:1674770712849}}function fcn_setStorySettings(t){"object"==typeof t&&(fcn_storySettings=t,localStorage.setItem("fcnStorySettings",JSON.stringify(t)))}function fcn_applyStorySettings(){"object"==typeof fcn_storySettings&&(_$$("[data-view]").forEach((t=>{t.dataset.view="grid"==fcn_storySettings.view?"grid":"list"})),_$$("[data-order]").forEach((t=>{t.dataset.order="desc"==fcn_storySettings.order?"desc":"asc"})))}function fcn_toggleStoryTab(t){_$$(".story__article ._current").forEach((t=>{t.classList.remove("_current")})),_$$$(t.dataset.target).classList.add("_current"),_$$$("tabs").dataset.current=t.dataset.target,t.classList.add("_current")}function fcn_loadStoryComments(){let t;_$(".load-more-list-item").remove(),_$(".comments-loading-placeholder").classList.remove("hidden"),fcn_ajaxGet({post_id:fcn_inlineStorage.postId,page:fcn_storyCommentPage},"get_story_comments").then((e=>{e.success?(_$(".fictioneer-comments__list > ul").innerHTML+=e.data.html,fcn_storyCommentPage++):e.data?.error&&(t=fcn_buildErrorNotice(e.data.error))})).catch((e=>{t=fcn_buildErrorNotice(e)})).then((()=>{_$(".comments-loading-placeholder").remove(),t&&_$(".fictioneer-comments__list > ul").appendChild(t)}))}fcn_applyStorySettings(),_$$$("button-toggle-chapter-order")?.addEventListener("click",(t=>{fcn_storySettings.order="asc"===t.currentTarget.dataset.order?"desc":"asc",fcn_setStorySettings(fcn_storySettings),fcn_applyStorySettings()})),_$$$("button-toggle-chapter-view")?.addEventListener("click",(t=>{fcn_storySettings.view="list"===t.currentTarget.dataset.view?"grid":"list",fcn_setStorySettings(fcn_storySettings),fcn_applyStorySettings()})),_$$(".chapter-group__folding-toggle").forEach((t=>{t.addEventListener("click",(t=>{const e=t.currentTarget.closest(".chapter-group[data-folded]");e&&(e.dataset.folded="true"==e.dataset.folded?"false":"true")}))})),_$$(".tabs__item").forEach((t=>{t.addEventListener("click",(t=>{fcn_toggleStoryTab(t.currentTarget)}))})),_$(".comment-section")?.addEventListener("click",(t=>{t.target?.classList.contains("load-more-comments-button")&&fcn_loadStoryComments()}));
|
2
js/utility.min.js
vendored
2
js/utility.min.js
vendored
File diff suppressed because one or more lines are too long
@ -23,7 +23,7 @@ if (
|
||||
$request_uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
|
||||
|
||||
// Check REST Request
|
||||
if ( strpos( $request_uri, 'wp-json/fictioneer_rest/v1/fictioneer_' ) !== false ) {
|
||||
if ( strpos( $request_uri, 'wp-json/fictioneer/' ) !== false ) {
|
||||
add_filter( 'option_active_plugins', 'fictioneer_exclude_plugins' );
|
||||
}
|
||||
|
||||
|
@ -189,13 +189,15 @@ function fcn_loadStoryComments() {
|
||||
_$('.load-more-list-item').remove();
|
||||
_$('.comments-loading-placeholder').classList.remove('hidden');
|
||||
|
||||
// Request
|
||||
fcn_ajaxGet({
|
||||
'action': 'fictioneer_ajax_request_story_comments',
|
||||
'post_id': fcn_inlineStorage.postId,
|
||||
'page': fcn_storyCommentPage
|
||||
})
|
||||
.then((response) => {
|
||||
// REST request
|
||||
fcn_ajaxGet(
|
||||
{
|
||||
'post_id': fcn_inlineStorage.postId,
|
||||
'page': fcn_storyCommentPage
|
||||
},
|
||||
'get_story_comments'
|
||||
)
|
||||
.then(response => {
|
||||
// Check for success
|
||||
if (response.success) {
|
||||
_$('.fictioneer-comments__list > ul').innerHTML += response.data.html;
|
||||
@ -204,7 +206,7 @@ function fcn_loadStoryComments() {
|
||||
errorNote = fcn_buildErrorNotice(response.data.error);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
errorNote = fcn_buildErrorNotice(error);
|
||||
})
|
||||
.then(() => {
|
||||
@ -212,7 +214,9 @@ function fcn_loadStoryComments() {
|
||||
_$('.comments-loading-placeholder').remove();
|
||||
|
||||
// Add error if any
|
||||
if (errorNote) _$('.fictioneer-comments__list > ul').appendChild(errorNote);
|
||||
if (errorNote) {
|
||||
_$('.fictioneer-comments__list > ul').appendChild(errorNote);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -46,18 +46,23 @@ const _$$$ = document.getElementById.bind(document);
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Make an AJAX POST request with the Fetch API.
|
||||
* Make a POST request with the Fetch API
|
||||
*
|
||||
* @since 5.0
|
||||
* @param {Object} data - The payload, including the action and nonce.
|
||||
* @param {String} url - Optional. The AJAX URL if different from the default.
|
||||
* @param {String} url - Optional. The request URL if different from the default.
|
||||
* @param {Object} headers - Optional. Headers for the request.
|
||||
* @returns {Promise} A Promise that resolves to the parsed JSON response if successful.
|
||||
*/
|
||||
|
||||
async function fcn_ajaxPost(data = {}, url = null, headers = {}) {
|
||||
// Auto-complete REST request if not a full URL
|
||||
if (url && !url.startsWith('http')) {
|
||||
url = fictioneer_ajax.rest_url + url;
|
||||
}
|
||||
|
||||
// Get URL if not provided
|
||||
if (!url) url = fictioneer_ajax.ajax_url;
|
||||
url = url ? url : fictioneer_ajax.ajax_url;
|
||||
|
||||
// Default headers
|
||||
final_headers = {
|
||||
@ -89,16 +94,21 @@ async function fcn_ajaxPost(data = {}, url = null, headers = {}) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an AJAX GET request with the Fetch API.
|
||||
* Make a GET request with the Fetch API.
|
||||
*
|
||||
* @since 5.0
|
||||
* @param {Object} data - The payload, including the action and nonce.
|
||||
* @param {String} url - Optional. The AJAX URL if different from the default.
|
||||
* @param {String} url - Optional. The request URL if different from the default.
|
||||
* @param {Object} headers - Optional. Headers for the request.
|
||||
* @return {JSON} The parsed JSON response if successful.
|
||||
*/
|
||||
|
||||
async function fcn_ajaxGet(data = {}, url = null, headers = {}) {
|
||||
// Auto-complete REST request if not a full URL
|
||||
if (url && !url.startsWith('http')) {
|
||||
url = fictioneer_ajax.rest_url + url;
|
||||
}
|
||||
|
||||
// Build URL
|
||||
url = url ? url : fictioneer_ajax.ajax_url;
|
||||
data = {...{'nonce': fcn_getNonce()}, ...data};
|
||||
@ -841,7 +851,7 @@ function fcn_html(...args) {
|
||||
// * @returns {Promise<number>} Promise that resolves with the average response time in milliseconds.
|
||||
// */
|
||||
|
||||
// async function benchmarkAjax(n = 1, data = {}, url = null, headers = {}) {
|
||||
// async function fcn_benchmarkAjax(n = 1, data = {}, url = null, headers = {}) {
|
||||
// let totalTime = 0;
|
||||
|
||||
// console.log(`Starting benchmark with ${n} AJAX requests...`);
|
||||
@ -864,3 +874,15 @@ function fcn_html(...args) {
|
||||
|
||||
// return averageTime;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Makes a GET request and prints the response to the console
|
||||
// *
|
||||
// * @param {Object} payload - The data payload to be sent with the AJAX request.
|
||||
// *
|
||||
// * @example fcn_ajaxPrintResponse({'action': 'the_function', 'fcn_fast_ajax': 1})
|
||||
// */
|
||||
|
||||
// function fcn_printAjaxResponse(payload) {
|
||||
// fcn_ajaxGet(payload).then((response) => { console.log(response); });
|
||||
// }
|
||||
|
Loading…
x
Reference in New Issue
Block a user