Make actions/filter no longer pluggable

You can remove them anyway, no need to sacrifice CPU cycles for this.
This commit is contained in:
Tetrakern 2023-08-08 22:45:55 +02:00
parent 6f6b591543
commit 373baa55c9
41 changed files with 6021 additions and 6304 deletions

View File

@ -165,37 +165,35 @@ if ( FICTIONEER_RELATIONSHIP_PURGE_ASSIST ) {
// REMEMBER WHEN CHAPTERS OF STORIES HAVE BEEN MODIFIED
// =============================================================================
if ( ! function_exists( 'fictioneer_remember_chapters_modified' ) ) {
/**
* Update story ACF field when associated chapter is updated
*
* The difference to the modified date is that this field is only updated when
* the chapters list changes, not when a chapter or story is updated in general.
*
* @since 4.0
* @link https://www.advancedcustomfields.com/resources/acf-update_value/
*
* @param mixed $value The field value.
* @param int|string $post_id The post ID where the value is saved.
*
* @return mixed The modified value.
*/
/**
* Update story ACF field when associated chapter is updated
*
* The difference to the modified date is that this field is only updated when
* the chapters list changes, not when a chapter or story is updated in general.
*
* @since 4.0
* @link https://www.advancedcustomfields.com/resources/acf-update_value/
*
* @param mixed $value The field value.
* @param int|string $post_id The post ID where the value is saved.
*
* @return mixed The modified value.
*/
function fictioneer_remember_chapters_modified( $value, $post_id ) {
$previous = fictioneer_get_field( 'fictioneer_story_chapters', $post_id );
$previous = is_array( $previous ) ? $previous : [];
$new = is_array( $value ) ? $value : [];
function fictioneer_remember_chapters_modified( $value, $post_id ) {
$previous = fictioneer_get_field( 'fictioneer_story_chapters', $post_id );
$previous = is_array( $previous ) ? $previous : [];
$new = is_array( $value ) ? $value : [];
if ( $previous !== $value ) {
update_post_meta( $post_id, 'fictioneer_chapters_modified', current_time( 'mysql' ) );
}
if ( count( $previous ) < count( $new ) ) {
update_post_meta( $post_id, 'fictioneer_chapters_added', current_time( 'mysql' ) );
}
return $value;
if ( $previous !== $value ) {
update_post_meta( $post_id, 'fictioneer_chapters_modified', current_time( 'mysql' ) );
}
if ( count( $previous ) < count( $new ) ) {
update_post_meta( $post_id, 'fictioneer_chapters_added', current_time( 'mysql' ) );
}
return $value;
}
add_filter( 'acf/update_value/name=fictioneer_story_chapters', 'fictioneer_remember_chapters_modified', 10, 2 );

View File

@ -203,103 +203,101 @@ add_filter( 'removable_query_args', 'fictioneer_removable_args' );
// LIMIT DEFAULT BLOCKS
// =============================================================================
if ( ! function_exists( 'fictioneer_allowed_block_types' ) ) {
/**
* Limit the available default blocks
*
* Fictioneer is has a particular and delicate content section, built around and
* for the main purpose of displaying prose. Other features, such as the ePUB
* converter heavily depend on _expected_ input or may break. There are certainly
* more possible but the initial selection has been chosen carefully.
*
* @since 4.0
*/
/**
* Limit the available default blocks
*
* Fictioneer is has a particular and delicate content section, built around and
* for the main purpose of displaying prose. Other features, such as the ePUB
* converter heavily depend on _expected_ input or may break. There are certainly
* more possible but the initial selection has been chosen carefully.
*
* @since 4.0
*/
function fictioneer_allowed_block_types() {
$allowed = array(
// WP Core
'core/image',
'core/paragraph',
'core/heading',
'core/list',
'core/list-item',
'core/gallery',
'core/quote',
'core/pullquote',
'core/buttons',
'core/button',
'core/audio',
'core/file',
'core/video',
'core/table',
'core/code',
'core/preformatted',
'core/html',
'core/separator',
'core/spacer',
'core/more',
'core/embed',
'core-embed/twitter',
'core-embed/youtube',
'core-embed/soundcloud',
'core-embed/spotify',
'core-embed/vimeo',
// Known plugins
'cloudinary/gallery',
'jetpack/business-hours',
'jetpack/button',
'jetpack/calendly',
'jetpack/contact-form',
'jetpack/field-text',
'jetpack/field-name',
'jetpack/field-email',
'jetpack/field-url',
'jetpack/field-date',
'jetpack/field-telephone',
'jetpack/field-textarea',
'jetpack/field-checkbox',
'jetpack/field-consent',
'jetpack/field-checkbox-multiple',
'jetpack/field-radio',
'jetpack/field-select',
'jetpack/contact-info',
'jetpack/address',
'jetpack/email',
'jetpack/phone',
'jetpack/eventbrite',
'jetpack/gif',
'jetpack/google-calendar',
'jetpack/image-compare',
'jetpack/instagram-gallery',
'jetpack/mailchimp',
'jetpack/map',
'jetpack/markdown',
'jetpack/opentable',
'jetpack/pinterest',
'jetpack/podcast-player',
'jetpack/rating-star',
'jetpack/recurring-payments',
'jetpack/repeat-visitor',
'jetpack/revue',
'jetpack/send-a-message',
'jetpack/whatsapp-button',
'jetpack/slideshow',
'jetpack/story',
'jetpack/subscriptions',
'jetpack/tiled-gallery',
'jetpack/payments-intro',
'jetpack/payment-buttons'
);
function fictioneer_allowed_block_types() {
$allowed = array(
// WP Core
'core/image',
'core/paragraph',
'core/heading',
'core/list',
'core/list-item',
'core/gallery',
'core/quote',
'core/pullquote',
'core/buttons',
'core/button',
'core/audio',
'core/file',
'core/video',
'core/table',
'core/code',
'core/preformatted',
'core/html',
'core/separator',
'core/spacer',
'core/more',
'core/embed',
'core-embed/twitter',
'core-embed/youtube',
'core-embed/soundcloud',
'core-embed/spotify',
'core-embed/vimeo',
// Known plugins
'cloudinary/gallery',
'jetpack/business-hours',
'jetpack/button',
'jetpack/calendly',
'jetpack/contact-form',
'jetpack/field-text',
'jetpack/field-name',
'jetpack/field-email',
'jetpack/field-url',
'jetpack/field-date',
'jetpack/field-telephone',
'jetpack/field-textarea',
'jetpack/field-checkbox',
'jetpack/field-consent',
'jetpack/field-checkbox-multiple',
'jetpack/field-radio',
'jetpack/field-select',
'jetpack/contact-info',
'jetpack/address',
'jetpack/email',
'jetpack/phone',
'jetpack/eventbrite',
'jetpack/gif',
'jetpack/google-calendar',
'jetpack/image-compare',
'jetpack/instagram-gallery',
'jetpack/mailchimp',
'jetpack/map',
'jetpack/markdown',
'jetpack/opentable',
'jetpack/pinterest',
'jetpack/podcast-player',
'jetpack/rating-star',
'jetpack/recurring-payments',
'jetpack/repeat-visitor',
'jetpack/revue',
'jetpack/send-a-message',
'jetpack/whatsapp-button',
'jetpack/slideshow',
'jetpack/story',
'jetpack/subscriptions',
'jetpack/tiled-gallery',
'jetpack/payments-intro',
'jetpack/payment-buttons'
);
if (
! get_option( 'fictioneer_strip_shortcodes_for_non_administrators' ) ||
current_user_can( 'administrator' )
) {
$allowed[] = 'core/shortcode';
}
return $allowed;
if (
! get_option( 'fictioneer_strip_shortcodes_for_non_administrators' ) ||
current_user_can( 'administrator' )
) {
$allowed[] = 'core/shortcode';
}
return $allowed;
}
if ( ! get_option( 'fictioneer_enable_all_blocks' ) ) {
@ -377,27 +375,25 @@ if ( get_option( 'fictioneer_admin_reduce_subscriber_profile' ) ) {
// LIMIT AUTHORS TO OWN POSTS/PAGES
// =============================================================================
if ( ! function_exists( 'fictioneer_limit_authors_to_own_posts_and_pages' ) ) {
/**
* Limit authors to own posts and pages
*
* @since 5.0
*/
/**
* Limit authors to own posts and pages
*
* @since 5.0
*/
function fictioneer_limit_authors_to_own_posts_and_pages( $query ) {
global $pagenow;
function fictioneer_limit_authors_to_own_posts_and_pages( $query ) {
global $pagenow;
// Abort conditions...
if ( ! $query->is_admin || 'edit.php' != $pagenow ) return $query;
// Abort conditions...
if ( ! $query->is_admin || 'edit.php' != $pagenow ) return $query;
// Add author to query unless user is supposed to see other posts/pages
if ( ! current_user_can( 'edit_others_posts' ) ) {
$query->set( 'author', get_current_user_id() );
}
// Return modified query
return $query;
// Add author to query unless user is supposed to see other posts/pages
if ( ! current_user_can( 'edit_others_posts' ) ) {
$query->set( 'author', get_current_user_id() );
}
// Return modified query
return $query;
}
add_filter( 'pre_get_posts', 'fictioneer_limit_authors_to_own_posts_and_pages' );

View File

@ -34,132 +34,130 @@ if ( ! function_exists( 'fictioneer_discord_send_message' ) ) {
// POST COMMENT TO DISCORD
// =============================================================================
if ( ! function_exists( 'fictioneer_post_comment_to_discord' ) ) {
/**
* Sends a comment as message to a Discord channel
*
* @since 4.0
* @see fictioneer_discord_send_message()
*
* @param int $comment_id The comment ID.
* @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
*/
/**
* Sends a comment as message to a Discord channel
*
* @since 4.0
* @see fictioneer_discord_send_message()
*
* @param int $comment_id The comment ID.
* @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
*/
function fictioneer_post_comment_to_discord( $comment_id, $comment_approved ) {
// Exit conditions
if ( empty( get_option( 'fictioneer_discord_channel_comments_webhook' ) ) ) return;
function fictioneer_post_comment_to_discord( $comment_id, $comment_approved ) {
// Exit conditions
if ( empty( get_option( 'fictioneer_discord_channel_comments_webhook' ) ) ) return;
// Setup
$comment = get_comment( $comment_id );
$comment_type = ucfirst( get_comment_type( $comment_id ) );
$comment_status = wp_get_comment_status( $comment );
$comment_avatar_url = get_avatar_url( $comment );
$post = get_post( $comment->comment_post_ID );
$user = get_user_by( 'id', $comment->user_id );
// Setup
$comment = get_comment( $comment_id );
$comment_type = ucfirst( get_comment_type( $comment_id ) );
$comment_status = wp_get_comment_status( $comment );
$comment_avatar_url = get_avatar_url( $comment );
$post = get_post( $comment->comment_post_ID );
$user = get_user_by( 'id', $comment->user_id );
if ( $user && ! empty( $user->fictioneer_external_avatar_url ) ) {
$comment_avatar_url = $user->fictioneer_external_avatar_url;
}
if ( $user && ! empty( $user->fictioneer_external_avatar_url ) ) {
$comment_avatar_url = $user->fictioneer_external_avatar_url;
}
// Message
$message = array(
'content' => null,
'username' => _x( 'Comment Stream', 'Discord message bot name.', 'fictioneer' ),
'embeds' => array(
array(
'title' => html_entity_decode( get_the_title( $post ) ),
'description' => html_entity_decode( get_comment_excerpt( $comment ) ),
'url' => get_comment_link( $comment ),
'color' => $comment_status == 'approved' ? '9692513' : '14112322',
'fields' => array(
array(
'name' => _x( 'Status', 'Discord message "Status" field.', 'fictioneer' ),
'value' => ucfirst( $comment_status ),
'inline' => true
),
array(
'name' => _x( 'Comment ID', 'Discord message "Comment ID" field.', 'fictioneer' ),
'value' => $comment_id,
'inline' => true
)
// Message
$message = array(
'content' => null,
'username' => _x( 'Comment Stream', 'Discord message bot name.', 'fictioneer' ),
'embeds' => array(
array(
'title' => html_entity_decode( get_the_title( $post ) ),
'description' => html_entity_decode( get_comment_excerpt( $comment ) ),
'url' => get_comment_link( $comment ),
'color' => $comment_status == 'approved' ? '9692513' : '14112322',
'fields' => array(
array(
'name' => _x( 'Status', 'Discord message "Status" field.', 'fictioneer' ),
'value' => ucfirst( $comment_status ),
'inline' => true
),
'author' => array(
'name' => $comment->comment_author,
'icon_url' => $comment_avatar_url
),
'timestamp' => date_format( date_create( $comment->comment_date ), 'c' )
)
array(
'name' => _x( 'Comment ID', 'Discord message "Comment ID" field.', 'fictioneer' ),
'value' => $comment_id,
'inline' => true
)
),
'author' => array(
'name' => $comment->comment_author,
'icon_url' => $comment_avatar_url
),
'timestamp' => date_format( date_create( $comment->comment_date ), 'c' )
)
)
);
// Has parent comment?
if ( $comment->comment_parent ) {
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'Reply to', 'Discord message "Reply to" field.', 'fictioneer' ),
'value' => get_comment( $comment->comment_parent )->comment_author,
'inline' => true
);
} else {
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'Reply to', 'Discord message "Reply to" field.', 'fictioneer' ),
'value' => __( 'n/a', 'fictioneer' ),
'inline' => true
);
}
// Is chapter with story?
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post->ID );
if ( $story_id ) {
$message['embeds'][0]['footer'] = array(
'text' => sprintf(
_x( 'Story: %s', 'Discord message footer note.', 'fictioneer' ),
get_the_title( $story_id )
)
);
}
// Has parent comment?
if ( $comment->comment_parent ) {
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'Reply to', 'Discord message "Reply to" field.', 'fictioneer' ),
'value' => get_comment( $comment->comment_parent )->comment_author,
'inline' => true
);
} else {
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'Reply to', 'Discord message "Reply to" field.', 'fictioneer' ),
'value' => __( 'n/a', 'fictioneer' ),
'inline' => true
);
}
// Registered user?
if ( $user ) {
// Registered
$role = translate_user_role( wp_roles()->roles[ $user->roles[0] ]['name'] );
// Is chapter with story?
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post->ID );
if ( $story_id ) {
$message['embeds'][0]['footer'] = array(
'text' => sprintf(
_x( 'Story: %s', 'Discord message footer note.', 'fictioneer' ),
get_the_title( $story_id )
)
);
}
// Registered user?
if ( $user ) {
// Registered
$role = translate_user_role( wp_roles()->roles[ $user->roles[0] ]['name'] );
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'User Role', 'Discord message "User Role" field.', 'fictioneer' ),
'value' => $role,
'inline' => true
);
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'User ID', 'Discord message "User ID" field.', 'fictioneer' ),
'value' => $comment->user_id,
'inline' => true
);
} else {
// Not registered
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'User Role', 'Discord message "User Role" field.', 'fictioneer' ),
'value' => __( 'Guest', 'fictioneer' ),
'inline' => true
);
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'User ID', 'Discord message "User ID" field.', 'fictioneer' ),
'value' => __( 'n/a', 'fictioneer' ),
'inline' => true
);
}
// Comment type
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'Type', 'Discord message comment "Type" field.', 'fictioneer' ),
'value' => $comment_type,
'name' => _x( 'User Role', 'Discord message "User Role" field.', 'fictioneer' ),
'value' => $role,
'inline' => true
);
// Send to Discord
fictioneer_discord_send_message( get_option( 'fictioneer_discord_channel_comments_webhook' ), $message );
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'User ID', 'Discord message "User ID" field.', 'fictioneer' ),
'value' => $comment->user_id,
'inline' => true
);
} else {
// Not registered
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'User Role', 'Discord message "User Role" field.', 'fictioneer' ),
'value' => __( 'Guest', 'fictioneer' ),
'inline' => true
);
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'User ID', 'Discord message "User ID" field.', 'fictioneer' ),
'value' => __( 'n/a', 'fictioneer' ),
'inline' => true
);
}
// Comment type
$message['embeds'][0]['fields'][] = array(
'name' => _x( 'Type', 'Discord message comment "Type" field.', 'fictioneer' ),
'value' => $comment_type,
'inline' => true
);
// Send to Discord
fictioneer_discord_send_message( get_option( 'fictioneer_discord_channel_comments_webhook' ), $message );
}
add_action( 'comment_post', 'fictioneer_post_comment_to_discord', 99, 2 );

View File

@ -4,16 +4,14 @@
// ADD ROUTE
// =============================================================================
if ( ! function_exists( 'fictioneer_add_epub_download_endpoint' ) ) {
/**
* Add route to ePUB script
*
* @since Fictioneer 4.0
*/
/**
* Add route to ePUB script
*
* @since Fictioneer 4.0
*/
function fictioneer_add_epub_download_endpoint() {
add_rewrite_endpoint( FICTIONEER_EPUB_ENDPOINT, EP_ROOT );
}
function fictioneer_add_epub_download_endpoint() {
add_rewrite_endpoint( FICTIONEER_EPUB_ENDPOINT, EP_ROOT );
}
add_action( 'init', 'fictioneer_add_epub_download_endpoint', 10 );

View File

@ -4,219 +4,217 @@
// CONTACT FORM SUBMIT - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_submit_contact_form' ) ) {
/**
* Submit comment form via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
*/
/**
* Submit comment form via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
*/
function fictioneer_ajax_submit_contact_form() {
// Nonce (die on failure)
check_ajax_referer( 'fictioneer_nonce', 'nonce' );
function fictioneer_ajax_submit_contact_form() {
// Nonce (die on failure)
check_ajax_referer( 'fictioneer_nonce', 'nonce' );
// Emergency stop
if ( get_option( 'fictioneer_disable_contact_forms' ) ) {
wp_send_json_error( ['error' => _x( 'Contact forms have been disabled.', 'Contact form.', 'fictioneer' )] );
}
// Emergency stop
if ( get_option( 'fictioneer_disable_contact_forms' ) ) {
wp_send_json_error( ['error' => _x( 'Contact forms have been disabled.', 'Contact form.', 'fictioneer' )] );
}
// Validations
if ( empty( $_POST['message'] ) ) {
wp_send_json_error( ['error' => _x( 'Message field empty.', 'Contact form.', 'fictioneer' )] );
}
// Validations
if ( empty( $_POST['message'] ) ) {
wp_send_json_error( ['error' => _x( 'Message field empty.', 'Contact form.', 'fictioneer' )] );
}
if ( ! empty( $_POST['phone'] ) || filter_var( $_POST['terms'] ?? 0, FILTER_VALIDATE_BOOLEAN ) ) {
// Pretend the submission worked if honeypot is triggered
wp_send_json_success( ['success' => _x( 'Submission received!', 'Contact form.', 'fictioneer' )] );
}
if ( ! empty( $_POST['phone'] ) || filter_var( $_POST['terms'] ?? 0, FILTER_VALIDATE_BOOLEAN ) ) {
// Pretend the submission worked if honeypot is triggered
wp_send_json_success( ['success' => _x( 'Submission received!', 'Contact form.', 'fictioneer' )] );
}
if (
$_POST['message'] != wp_strip_all_tags( $_POST['message'] ) ||
( ! empty( $_POST['name'] ) && $_POST['name'] != wp_strip_all_tags( $_POST['name'] ) )
) {
// All fields are stripped of HTMl anyway, so this is only for the overly enthusiastic user.
wp_send_json_error( ['error' => _x( 'Illegal HTML detected.', 'Contact form.', 'fictioneer' )] );
}
if (
$_POST['message'] != wp_strip_all_tags( $_POST['message'] ) ||
( ! empty( $_POST['name'] ) && $_POST['name'] != wp_strip_all_tags( $_POST['name'] ) )
) {
// All fields are stripped of HTMl anyway, so this is only for the overly enthusiastic user.
wp_send_json_error( ['error' => _x( 'Illegal HTML detected.', 'Contact form.', 'fictioneer' )] );
}
if ( ! empty( $_POST['email'] ) && ! is_email( $_POST['email'] ) ) {
wp_send_json_error( ['error' => _x( 'Invalid email address.', 'Contact form.', 'fictioneer' )] );
}
if ( ! empty( $_POST['email'] ) && ! is_email( $_POST['email'] ) ) {
wp_send_json_error( ['error' => _x( 'Invalid email address.', 'Contact form.', 'fictioneer' )] );
}
if (
filter_var( $_POST['require_privacy_policy'] ?? 0, FILTER_VALIDATE_BOOLEAN ) &&
! filter_var( $_POST['privacy_policy'] ?? 0, FILTER_VALIDATE_BOOLEAN )
) {
// If the sender disables these fields, this is essentially acceptance
// since they went out of their way to manipulate the form.
wp_send_json_error( ['error' => _x( 'You need to accept the privacy policy.', 'Contact form.', 'fictioneer' )] );
}
if (
filter_var( $_POST['require_privacy_policy'] ?? 0, FILTER_VALIDATE_BOOLEAN ) &&
! filter_var( $_POST['privacy_policy'] ?? 0, FILTER_VALIDATE_BOOLEAN )
) {
// If the sender disables these fields, this is essentially acceptance
// since they went out of their way to manipulate the form.
wp_send_json_error( ['error' => _x( 'You need to accept the privacy policy.', 'Contact form.', 'fictioneer' )] );
}
// Setup
$user = wp_get_current_user();
$title = sanitize_text_field( $_POST['title'] ?? _x( 'Nameless Form', 'Contact form.', 'fictioneer' ) );
$message = sanitize_textarea_field( $_POST['message'] );
$email = sanitize_email( $_POST['email'] ?? '' );
$name = sanitize_text_field( $_POST['name'] ?? '' );
$headers = ['Content-Type: text/html; charset=UTF-8'];
$strings = [];
// Setup
$user = wp_get_current_user();
$title = sanitize_text_field( $_POST['title'] ?? _x( 'Nameless Form', 'Contact form.', 'fictioneer' ) );
$message = sanitize_textarea_field( $_POST['message'] );
$email = sanitize_email( $_POST['email'] ?? '' );
$name = sanitize_text_field( $_POST['name'] ?? '' );
$headers = ['Content-Type: text/html; charset=UTF-8'];
$strings = [];
// Strip HTML for good measure
$title = wp_strip_all_tags( $title );
$message = wpautop( wp_strip_all_tags( $message ) );
$name = wp_strip_all_tags( $name );
// Strip HTML for good measure
$title = wp_strip_all_tags( $title );
$message = wpautop( wp_strip_all_tags( $message ) );
$name = wp_strip_all_tags( $name );
// Add to $strings
$strings[] = $title;
$strings[] = $message;
$strings[] = $name;
// Add to $strings
$strings[] = $title;
$strings[] = $message;
$strings[] = $name;
// Email body...
$html = '<p><strong>' . sprintf( _x( 'Form submission: %s', 'Contact form.', 'fictioneer' ), $title ) . '</strong></p>';
$html .= '<fieldset>' . $message . '</fieldset>';
// Email body...
$html = '<p><strong>' . sprintf( _x( 'Form submission: %s', 'Contact form.', 'fictioneer' ), $title ) . '</strong></p>';
$html .= '<fieldset>' . $message . '</fieldset>';
// ... email field
if ( ! empty( $email ) ) {
$html .= '<p>' . sprintf( _x( '<strong>Email Address:</strong> %s', 'Contact form.', 'fictioneer' ), $email ) . '</p>';
}
// ... email field
if ( ! empty( $email ) ) {
$html .= '<p>' . sprintf( _x( '<strong>Email Address:</strong> %s', 'Contact form.', 'fictioneer' ), $email ) . '</p>';
}
// ... name field
if ( ! empty( $name ) ) {
$html .= '<p>' . sprintf( _x( '<strong>Name:</strong> %s', 'Contact form.', 'fictioneer' ), $name ) . '</p>';
}
// ... name field
if ( ! empty( $name ) ) {
$html .= '<p>' . sprintf( _x( '<strong>Name:</strong> %s', 'Contact form.', 'fictioneer' ), $name ) . '</p>';
}
// ... text fields
for ( $i = 1; $i <= 6; $i++ ) {
// Get label and value (if any)
$field_value = sanitize_text_field( $_POST[ "text_$i" ] ?? '' );
$field_label = sanitize_text_field( $_POST[ "text_label_$i" ] ?? '' );
// ... text fields
for ( $i = 1; $i <= 6; $i++ ) {
// Get label and value (if any)
$field_value = sanitize_text_field( $_POST[ "text_$i" ] ?? '' );
$field_label = sanitize_text_field( $_POST[ "text_label_$i" ] ?? '' );
// Skip if label is missing
if ( empty( $field_label ) ) continue;
// Build field
if ( ! empty( $field_value ) ) {
// Strip HTML for good measure
$field_value = wp_strip_all_tags( $field_value );
$field_label = wp_strip_all_tags( $field_label );
// Add to $strings
$strings[] = $field_value;
$strings[] = $field_value;
// Add to email body
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
$field_label,
$field_value
) . '</p>';
}
}
// ... checkboxes
for ( $i = 1; $i <= 6; $i++ ) {
// Get label and value (if any)
$field_value = filter_var( $_POST[ "check_$i" ] ?? 0, FILTER_VALIDATE_BOOLEAN );
$field_label = sanitize_text_field( $_POST[ "check_label_$i" ] ?? '' );
// Skip if label is missing
if ( empty( $field_label ) ) continue;
// Skip if label is missing
if ( empty( $field_label ) ) continue;
// Build field
if ( ! empty( $field_value ) ) {
// Strip HTML for good measure
$field_value = wp_strip_all_tags( $field_value );
$field_label = wp_strip_all_tags( $field_label );
// Add to $strings
$strings[] = $field_label;
$strings[] = $field_value;
$strings[] = $field_value;
// Build field
// Add to email body
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
$field_label,
$field_value ? __( 'True', 'fictioneer' ) : __( 'False', 'fictioneer' )
$field_value
) . '</p>';
}
// Hook for additional spam protection
do_action( 'fictioneer_contact_form_validation', $strings );
// ... IP and user agent if privacy policy acceptance is required
if ( filter_var( $_POST['require_privacy_policy'] ?? 0, FILTER_VALIDATE_BOOLEAN ) ) {
// IP (unreliable)
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
__( 'IP Address', 'fictioneer' ),
$_SERVER['REMOTE_ADDR'] ?? ''
) . '</p>';
// User agent (unreliable)
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
__( 'User Agent', 'fictioneer' ),
$_SERVER['HTTP_USER_AGENT'] ?? ''
) . '</p>';
}
// ... user if logged in
if ( is_user_logged_in() ) {
$user_info = get_userdata( $user->ID );
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
__( 'User', 'fictioneer' ),
sprintf( _x( '%1$s (%2$s)', 'Contact form.', 'fictioneer' ), $user_info->user_login, $user->ID )
) . '</p>';
}
// Check against disallow list (Settings > Discussion)
$offenders = fictioneer_check_comment_disallowed_list(
$name,
$email,
'',
$message,
$_SERVER['REMOTE_ADDR'] ?? '',
$_SERVER['HTTP_USER_AGENT'] ?? ''
);
// Only show error for keys in content, trash anything else as usual later.
// No need to tell someone his name or email address is blocked, etc.
if ( FICTIONEER_DISALLOWED_KEY_NOTICE && $offenders[0] && $offenders[1] ) {
wp_send_json_error( ['error' => __( 'Disallowed key found: "' . implode( ', ', $offenders[1] ) . '".', 'fictioneer' )] );
} elseif ( $offenders[0] ) {
wp_send_json_error( ['error' => __( 'Disallowed keys found.', 'fictioneer' )] );
}
// Addresses
$to_addresses = array_filter( explode( "\n", get_option( 'fictioneer_contact_email_addresses' ) ) );
$to_addresses = empty( $to_addresses ) ? [get_bloginfo( 'admin_email' )] : $to_addresses;
$from_address = get_option( 'fictioneer_system_email_address' );
// Headers
if ( ! empty( $from_address ) ) {
$from_name = get_option( 'fictioneer_system_email_name' );
$from_name = empty ( $from_name ) ? FICTIONEER_SITE_NAME : $from_name;
$headers[] = 'From: ' . trim( $from_name ) . ' <' . trim( $from_address ) . '>';
}
// Send email to each recipient
foreach ( $to_addresses as $to ) {
$to = sanitize_email( $to );
// Skip if not valid email address
if ( ! is_email( $to ) ) continue;
// Send email
wp_mail(
$to,
sprintf( _x( 'Form submission: %s', 'Contact form.', 'fictioneer' ), $title ),
$html,
$headers
);
}
// Response
wp_send_json_success( ['success' => _x( 'Submission received!', 'Contact form.', 'fictioneer' )] );
}
// ... checkboxes
for ( $i = 1; $i <= 6; $i++ ) {
// Get label and value (if any)
$field_value = filter_var( $_POST[ "check_$i" ] ?? 0, FILTER_VALIDATE_BOOLEAN );
$field_label = sanitize_text_field( $_POST[ "check_label_$i" ] ?? '' );
// Skip if label is missing
if ( empty( $field_label ) ) continue;
// Strip HTML for good measure
$field_label = wp_strip_all_tags( $field_label );
// Add to $strings
$strings[] = $field_label;
// Build field
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
$field_label,
$field_value ? __( 'True', 'fictioneer' ) : __( 'False', 'fictioneer' )
) . '</p>';
}
// Hook for additional spam protection
do_action( 'fictioneer_contact_form_validation', $strings );
// ... IP and user agent if privacy policy acceptance is required
if ( filter_var( $_POST['require_privacy_policy'] ?? 0, FILTER_VALIDATE_BOOLEAN ) ) {
// IP (unreliable)
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
__( 'IP Address', 'fictioneer' ),
$_SERVER['REMOTE_ADDR'] ?? ''
) . '</p>';
// User agent (unreliable)
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
__( 'User Agent', 'fictioneer' ),
$_SERVER['HTTP_USER_AGENT'] ?? ''
) . '</p>';
}
// ... user if logged in
if ( is_user_logged_in() ) {
$user_info = get_userdata( $user->ID );
$html .= '<p>' . sprintf(
_x( '<strong>%1$s:</strong> %2$s', 'Contact form.', 'fictioneer' ),
__( 'User', 'fictioneer' ),
sprintf( _x( '%1$s (%2$s)', 'Contact form.', 'fictioneer' ), $user_info->user_login, $user->ID )
) . '</p>';
}
// Check against disallow list (Settings > Discussion)
$offenders = fictioneer_check_comment_disallowed_list(
$name,
$email,
'',
$message,
$_SERVER['REMOTE_ADDR'] ?? '',
$_SERVER['HTTP_USER_AGENT'] ?? ''
);
// Only show error for keys in content, trash anything else as usual later.
// No need to tell someone his name or email address is blocked, etc.
if ( FICTIONEER_DISALLOWED_KEY_NOTICE && $offenders[0] && $offenders[1] ) {
wp_send_json_error( ['error' => __( 'Disallowed key found: "' . implode( ', ', $offenders[1] ) . '".', 'fictioneer' )] );
} elseif ( $offenders[0] ) {
wp_send_json_error( ['error' => __( 'Disallowed keys found.', 'fictioneer' )] );
}
// Addresses
$to_addresses = array_filter( explode( "\n", get_option( 'fictioneer_contact_email_addresses' ) ) );
$to_addresses = empty( $to_addresses ) ? [get_bloginfo( 'admin_email' )] : $to_addresses;
$from_address = get_option( 'fictioneer_system_email_address' );
// Headers
if ( ! empty( $from_address ) ) {
$from_name = get_option( 'fictioneer_system_email_name' );
$from_name = empty ( $from_name ) ? FICTIONEER_SITE_NAME : $from_name;
$headers[] = 'From: ' . trim( $from_name ) . ' <' . trim( $from_address ) . '>';
}
// Send email to each recipient
foreach ( $to_addresses as $to ) {
$to = sanitize_email( $to );
// Skip if not valid email address
if ( ! is_email( $to ) ) continue;
// Send email
wp_mail(
$to,
sprintf( _x( 'Form submission: %s', 'Contact form.', 'fictioneer' ), $title ),
$html,
$headers
);
}
// Response
wp_send_json_success( ['success' => _x( 'Submission received!', 'Contact form.', 'fictioneer' )] );
}
add_action( 'wp_ajax_fictioneer_ajax_submit_contact_form', 'fictioneer_ajax_submit_contact_form' );
add_action( 'wp_ajax_nopriv_fictioneer_ajax_submit_contact_form', 'fictioneer_ajax_submit_contact_form' );

View File

@ -42,16 +42,14 @@ define(
// SETUP
// =============================================================================
if ( ! function_exists( 'fictioneer_add_oauth2_endpoint' ) ) {
/**
* Add route to OAuth script
*
* @since Fictioneer 4.0
*/
/**
* Add route to OAuth script
*
* @since Fictioneer 4.0
*/
function fictioneer_add_oauth2_endpoint() {
add_rewrite_endpoint( FICTIONEER_OAUTH_ENDPOINT, EP_ROOT );
}
function fictioneer_add_oauth2_endpoint() {
add_rewrite_endpoint( FICTIONEER_OAUTH_ENDPOINT, EP_ROOT );
}
if ( get_option( 'fictioneer_enable_oauth' ) ) {
@ -160,148 +158,146 @@ if ( ! function_exists( 'fictioneer_get_oauth_links' ) ) {
// PROCESS
// =============================================================================
if ( ! function_exists( 'fictioneer_handle_oauth' ) ) {
/**
* Handle OAuth2 requests made to the OAuth2 route
*
* After an initial validation, delegates to the current OAuth2 steps based on
* the action (GET) and session variables. Each provider differs a bit, but the
* protocol is the same. First, you have to request a CODE with the pre-defined
* permissions (SCOPE) that requires user confirmation. This is secured with a
* cryptic key (STATE). Once you got the CODE, you need to make another request
* for a TOKEN, which is then used to make yet another request for the user data
* to authenticate the user. The connection is severed after that.
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/hooks/template_redirect/
* @link https://dev.twitch.tv/docs/authentication
* @link https://discord.com/developers/docs/topics/oauth2
* @link https://docs.patreon.com/#step-1-registering-your-client
* @link https://developers.google.com/identity/protocols/oauth2
*/
/**
* Handle OAuth2 requests made to the OAuth2 route
*
* After an initial validation, delegates to the current OAuth2 steps based on
* the action (GET) and session variables. Each provider differs a bit, but the
* protocol is the same. First, you have to request a CODE with the pre-defined
* permissions (SCOPE) that requires user confirmation. This is secured with a
* cryptic key (STATE). Once you got the CODE, you need to make another request
* for a TOKEN, which is then used to make yet another request for the user data
* to authenticate the user. The connection is severed after that.
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/hooks/template_redirect/
* @link https://dev.twitch.tv/docs/authentication
* @link https://discord.com/developers/docs/topics/oauth2
* @link https://docs.patreon.com/#step-1-registering-your-client
* @link https://developers.google.com/identity/protocols/oauth2
*/
function fictioneer_handle_oauth() {
// Check whether this is the OAuth2 route
if ( is_null( get_query_var( FICTIONEER_OAUTH_ENDPOINT, null ) ) ) return;
function fictioneer_handle_oauth() {
// Check whether this is the OAuth2 route
if ( is_null( get_query_var( FICTIONEER_OAUTH_ENDPOINT, null ) ) ) return;
// Setup
fictioneer_set_oauth_constants();
$note = '';
// Setup
fictioneer_set_oauth_constants();
$note = '';
// Check nonce for initial call but not once a STATE is set
if (
! STATE &&
(
! isset( $_GET['oauth_nonce'] ) ||
! wp_verify_nonce( $_GET['oauth_nonce'], 'authenticate' )
// Check nonce for initial call but not once a STATE is set
if (
! STATE &&
(
! isset( $_GET['oauth_nonce'] ) ||
! wp_verify_nonce( $_GET['oauth_nonce'], 'authenticate' )
)
) {
fictioneer_oauth2_exit_and_return();
}
// Exit on error
if ( ERROR ) fictioneer_oauth2_exit_and_return();
// Logout
if ( ACTION === 'logout' ) {
wp_logout();
fictioneer_oauth2_exit_and_return( ANCHOR ? RETURN_URL . '#' . ANCHOR : RETURN_URL );
}
// Check whether oauth is working
if (
! get_option( 'fictioneer_enable_oauth' ) ||
! OAUTH2_CLIENT_ID ||
! OAUTH2_CLIENT_SECRET
) {
fictioneer_oauth2_exit_and_return();
}
// Check for MERGE if user is not logged in
if ( ! is_user_logged_in() && MERGE == '1' ) {
fictioneer_oauth2_exit_and_return();
}
// Check for MERGE if user is already logged in
if (
is_user_logged_in() &&
(
MERGE != '1' &&
! isset( $_SESSION['current_user_id'] )
)
) {
fictioneer_oauth2_exit_and_return();
}
// Get code
if ( ACTION === 'login' ) {
fictioneer_get_oauth_code();
}
// Security check
if ( ! STATE || $_SESSION['state'] != STATE ) fictioneer_oauth2_exit_and_return();
// Get token and delegate to login/register
if ( ! empty( CODE ) ) {
$token = fictioneer_get_oauth_token(
FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['token'],
array(
'grant_type' => 'authorization_code',
'client_id' => OAUTH2_CLIENT_ID,
'client_secret' => OAUTH2_CLIENT_SECRET,
'redirect_uri' => REDIRECT_URL,
'code' => CODE,
'scope' => FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['scope']
)
) {
fictioneer_oauth2_exit_and_return();
);
// Access token successfully retrieved?
$access_token = isset( $token->access_token ) ? $token->access_token : null;
if ( ! $access_token ) fictioneer_oauth2_exit_and_return();
// Delegate to respective channel function
switch ( CHANNEL ) {
case 'discord':
$note = fictioneer_process_oauth_discord( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
case 'twitch':
$note = fictioneer_process_oauth_twitch( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
case 'google':
$note = fictioneer_process_oauth_google( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
case 'patreon':
$note = fictioneer_process_oauth_patreon( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
}
// Exit on error
if ( ERROR ) fictioneer_oauth2_exit_and_return();
// Logout
if ( ACTION === 'logout' ) {
wp_logout();
fictioneer_oauth2_exit_and_return( ANCHOR ? RETURN_URL . '#' . ANCHOR : RETURN_URL );
// Error: Email already taken by another account
if ( ! is_user_logged_in() ) {
$return_url = ( $_SESSION['return_url'] ) ? urldecode( $_SESSION['return_url'] ) : RETURN_URL;
$return_url .= '?failure=' . $note;
$return_url = ( $_SESSION['anchor'] ) ? $return_url . '#' . $_SESSION['anchor'] : $return_url;
fictioneer_oauth2_exit_and_return( $return_url );
}
// Check whether oauth is working
if (
! get_option( 'fictioneer_enable_oauth' ) ||
! OAUTH2_CLIENT_ID ||
! OAUTH2_CLIENT_SECRET
) {
fictioneer_oauth2_exit_and_return();
// Success: Merged into account
if ( $note == 'merged' ) {
$return_url = ( $_SESSION['return_url'] ) ? urldecode( $_SESSION['return_url'] ) : RETURN_URL;
$return_url .= '?success=oauth_merged_' . CHANNEL;
$return_url = ( $_SESSION['anchor'] ) ? $return_url . '#' . $_SESSION['anchor'] : $return_url;
fictioneer_oauth2_exit_and_return( $return_url );
}
// Check for MERGE if user is not logged in
if ( ! is_user_logged_in() && MERGE == '1' ) {
fictioneer_oauth2_exit_and_return();
// Success: New user registered
if ( $note == 'new' ) {
$return_url = ( $_SESSION['return_url'] ) ? urldecode( $_SESSION['return_url'] ) : RETURN_URL;
$return_url .= '?success=oauth_new_subscriber';
$return_url = ( $_SESSION['anchor'] ) ? $return_url . '#' . $_SESSION['anchor'] : $return_url;
fictioneer_oauth2_exit_and_return( $return_url );
}
// Check for MERGE if user is already logged in
if (
is_user_logged_in() &&
(
MERGE != '1' &&
! isset( $_SESSION['current_user_id'] )
)
) {
fictioneer_oauth2_exit_and_return();
}
// Get code
if ( ACTION === 'login' ) {
fictioneer_get_oauth_code();
}
// Security check
if ( ! STATE || $_SESSION['state'] != STATE ) fictioneer_oauth2_exit_and_return();
// Get token and delegate to login/register
if ( ! empty( CODE ) ) {
$token = fictioneer_get_oauth_token(
FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['token'],
array(
'grant_type' => 'authorization_code',
'client_id' => OAUTH2_CLIENT_ID,
'client_secret' => OAUTH2_CLIENT_SECRET,
'redirect_uri' => REDIRECT_URL,
'code' => CODE,
'scope' => FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['scope']
)
);
// Access token successfully retrieved?
$access_token = isset( $token->access_token ) ? $token->access_token : null;
if ( ! $access_token ) fictioneer_oauth2_exit_and_return();
// Delegate to respective channel function
switch ( CHANNEL ) {
case 'discord':
$note = fictioneer_process_oauth_discord( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
case 'twitch':
$note = fictioneer_process_oauth_twitch( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
case 'google':
$note = fictioneer_process_oauth_google( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
case 'patreon':
$note = fictioneer_process_oauth_patreon( FICIONEER_OAUTH_API_ENDPOINTS[CHANNEL]['user'], $access_token );
break;
}
// Error: Email already taken by another account
if ( ! is_user_logged_in() ) {
$return_url = ( $_SESSION['return_url'] ) ? urldecode( $_SESSION['return_url'] ) : RETURN_URL;
$return_url .= '?failure=' . $note;
$return_url = ( $_SESSION['anchor'] ) ? $return_url . '#' . $_SESSION['anchor'] : $return_url;
fictioneer_oauth2_exit_and_return( $return_url );
}
// Success: Merged into account
if ( $note == 'merged' ) {
$return_url = ( $_SESSION['return_url'] ) ? urldecode( $_SESSION['return_url'] ) : RETURN_URL;
$return_url .= '?success=oauth_merged_' . CHANNEL;
$return_url = ( $_SESSION['anchor'] ) ? $return_url . '#' . $_SESSION['anchor'] : $return_url;
fictioneer_oauth2_exit_and_return( $return_url );
}
// Success: New user registered
if ( $note == 'new' ) {
$return_url = ( $_SESSION['return_url'] ) ? urldecode( $_SESSION['return_url'] ) : RETURN_URL;
$return_url .= '?success=oauth_new_subscriber';
$return_url = ( $_SESSION['anchor'] ) ? $return_url . '#' . $_SESSION['anchor'] : $return_url;
fictioneer_oauth2_exit_and_return( $return_url );
}
// Finish
fictioneer_oauth2_exit_and_return();
}
// Finish
fictioneer_oauth2_exit_and_return();
}
}
add_action( 'template_redirect', 'fictioneer_handle_oauth', 10 );

View File

@ -10,28 +10,26 @@
// RESTRICT SUBSCRIBERS ROLE
// =============================================================================
if ( ! function_exists( 'fictioneer_block_subscribers_from_admin' ) ) {
/**
* Prevent subscribers from accessing the admin panel
*
* Subscribers have a custom frontend user profile and therefore no need to
* access the admin panel at all. Only higher roles are granted access, although
* admin-specific actions such as AJAX requests are still permitted.
*
* @since Fictioneer 4.0
*/
/**
* Prevent subscribers from accessing the admin panel
*
* Subscribers have a custom frontend user profile and therefore no need to
* access the admin panel at all. Only higher roles are granted access, although
* admin-specific actions such as AJAX requests are still permitted.
*
* @since Fictioneer 4.0
*/
function fictioneer_block_subscribers_from_admin() {
// Redirect back to Home
if (
is_admin() &&
! current_user_can( 'edit_posts' ) &&
! current_user_can( 'moderate_comments' ) &&
! ( defined( 'DOING_AJAX' ) && DOING_AJAX )
) {
wp_redirect( home_url() );
exit;
}
function fictioneer_block_subscribers_from_admin() {
// Redirect back to Home
if (
is_admin() &&
! current_user_can( 'edit_posts' ) &&
! current_user_can( 'moderate_comments' ) &&
! ( defined( 'DOING_AJAX' ) && DOING_AJAX )
) {
wp_redirect( home_url() );
exit;
}
}
@ -39,37 +37,33 @@ if ( get_option( 'fictioneer_block_subscribers_from_admin' ) ) {
add_action( 'init', 'fictioneer_block_subscribers_from_admin' );
}
if ( ! function_exists( 'fictioneer_reduce_subscriber_dashboard_widgets' ) ) {
/**
* Remove admin dashboard widgets for subscribers
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
/**
* Remove admin dashboard widgets for subscribers
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
function fictioneer_reduce_subscriber_dashboard_widgets() {
global $wp_meta_boxes;
function fictioneer_reduce_subscriber_dashboard_widgets() {
global $wp_meta_boxes;
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
if ( ! function_exists( 'fictioneer_reduce_subscriber_admin_panel' ) ) {
/**
* Remove admin menu pages for subscribers
*
* @since Fictioneer 5.0
*/
/**
* Remove admin menu pages for subscribers
*
* @since Fictioneer 5.0
*/
function fictioneer_reduce_subscriber_admin_panel() {
// Remove menu pages
remove_menu_page( 'index.php' ); // Dashboard
}
function fictioneer_reduce_subscriber_admin_panel() {
// Remove menu pages
remove_menu_page( 'index.php' ); // Dashboard
}
// Apply restrictions to subscribers
@ -83,108 +77,98 @@ if ( fictioneer_has_role( get_current_user_id(), 'subscriber' ) ) {
// RESTRICT FICTIONEER MODERATOR ROLE
// =============================================================================
if ( ! function_exists( 'fictioneer_reduce_moderator_admin_panel' ) ) {
/**
* Remove admin menu pages for moderators
*
* @since Fictioneer 5.0
*/
/**
* Remove admin menu pages for moderators
*
* @since Fictioneer 5.0
*/
function fictioneer_reduce_moderator_admin_panel() {
// Remove menu pages
remove_menu_page( 'edit.php' );
remove_menu_page( 'tools.php' );
remove_menu_page( 'plugins.php' );
remove_menu_page( 'themes.php' );
function fictioneer_reduce_moderator_admin_panel() {
// Remove menu pages
remove_menu_page( 'edit.php' );
remove_menu_page( 'tools.php' );
remove_menu_page( 'plugins.php' );
remove_menu_page( 'themes.php' );
}
/**
* Remove admin dashboard widgets for moderators
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
function fictioneer_reduce_moderator_dashboard_widgets() {
global $wp_meta_boxes;
// Keep
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
/**
* Remove items from admin bar for moderators
*
* @since Fictioneer 5.0
*/
function fictioneer_reduce_moderator_admin_bar() {
global $wp_admin_bar;
// Remove all [+New] items
$wp_admin_bar->remove_node( 'new-content' );
}
/**
* Restrict access to admin pages/actions for moderators
*
* @since Fictioneer 5.0
*/
function fictioneer_restrict_moderator_menu_access() {
// Setup
$screen = get_current_screen();
// Block access
if (
in_array(
$screen->id,
['tools', 'export', 'import', 'site-health', 'export-personal-data', 'erase-personal-data', 'themes', 'customize', 'nav-menus', 'theme-editor', 'users', 'user-new', 'options-general', 'post-new']
) ||
! empty( $screen->post_type )
) {
wp_die( __( 'Access denied.', 'fictioneer' ) );
}
}
if ( ! function_exists( 'fictioneer_reduce_moderator_dashboard_widgets' ) ) {
/**
* Remove admin dashboard widgets for moderators
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
/**
* Restrict access to admin pages/actions for moderators
*
* Prevent moderators from editing the comment content, which is rarely a good action.
* Doing this via JS is a terrible solution but better than nothing.
*
* @since Fictioneer 5.0
* @todo Do this server-side to prevent savvy moderators from circumventing it.
*/
function fictioneer_reduce_moderator_dashboard_widgets() {
global $wp_meta_boxes;
// Keep
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
}
if ( ! function_exists( 'fictioneer_reduce_moderator_admin_bar' ) ) {
/**
* Remove items from admin bar for moderators
*
* @since Fictioneer 5.0
*/
function fictioneer_reduce_moderator_admin_bar() {
global $wp_admin_bar;
// Remove all [+New] items
$wp_admin_bar->remove_node( 'new-content' );
}
}
if ( ! function_exists( 'fictioneer_restrict_moderator_menu_access' ) ) {
/**
* Restrict access to admin pages/actions for moderators
*
* @since Fictioneer 5.0
*/
function fictioneer_restrict_moderator_menu_access() {
// Setup
$screen = get_current_screen();
// Block access
if (
in_array(
$screen->id,
['tools', 'export', 'import', 'site-health', 'export-personal-data', 'erase-personal-data', 'themes', 'customize', 'nav-menus', 'theme-editor', 'users', 'user-new', 'options-general', 'post-new']
) ||
! empty( $screen->post_type )
) {
wp_die( __( 'Access denied.', 'fictioneer' ) );
}
}
}
if ( ! function_exists( 'fictioneer_disable_moderator_comment_edit' ) ) {
/**
* Restrict access to admin pages/actions for moderators
*
* Prevent moderators from editing the comment content, which is rarely a good action.
* Doing this via JS is a terrible solution but better than nothing.
*
* @since Fictioneer 5.0
* @todo Do this server-side to prevent savvy moderators from circumventing it.
*/
function fictioneer_disable_moderator_comment_edit() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('#qt_content_toolbar').remove();
$('.wp-editor-area').prop('disabled', true);
$('.wp-editor-area').prop('name', '');
});"
);
}
function fictioneer_disable_moderator_comment_edit() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('#qt_content_toolbar').remove();
$('.wp-editor-area').prop('disabled', true);
$('.wp-editor-area').prop('name', '');
});"
);
}
// Apply restrictions to fcn_moderators
@ -203,92 +187,84 @@ if (
// RESTRICT EDITOR ROLE
// =============================================================================
if ( ! function_exists( 'fictioneer_restrict_editor_menu_access' ) ) {
/**
* Restrict access to admin pages/actions for editors
*
* @since Fictioneer 5.0
*/
/**
* Restrict access to admin pages/actions for editors
*
* @since Fictioneer 5.0
*/
function fictioneer_restrict_editor_menu_access() {
// Setup
$screen = get_current_screen();
function fictioneer_restrict_editor_menu_access() {
// Setup
$screen = get_current_screen();
// Block access
if (
in_array(
$screen->id,
['tools', 'export', 'import', 'site-health', 'export-personal-data', 'erase-personal-data', 'themes', 'customize', 'nav-menus', 'theme-editor', 'users', 'user-new', 'options-general', 'comment']
)
) {
wp_die( __( 'Access denied.', 'fictioneer' ) );
}
// Block access
if (
in_array(
$screen->id,
['tools', 'export', 'import', 'site-health', 'export-personal-data', 'erase-personal-data', 'themes', 'customize', 'nav-menus', 'theme-editor', 'users', 'user-new', 'options-general', 'comment']
)
) {
wp_die( __( 'Access denied.', 'fictioneer' ) );
}
}
if ( ! function_exists( 'fictioneer_reduce_editor_admin_bar' ) ) {
/**
* Remove items from admin bar for editors
*
* @since Fictioneer 5.0
*/
/**
* Remove items from admin bar for editors
*
* @since Fictioneer 5.0
*/
function fictioneer_reduce_editor_admin_bar() {
global $wp_admin_bar;
function fictioneer_reduce_editor_admin_bar() {
global $wp_admin_bar;
// Remove all [+New] items
$wp_admin_bar->remove_node( 'new-content' );
// Remove all [+New] items
$wp_admin_bar->remove_node( 'new-content' );
// Remove comments
$wp_admin_bar->remove_node( 'comments' );
}
// Remove comments
$wp_admin_bar->remove_node( 'comments' );
}
if ( ! function_exists( 'fictioneer_reduce_editor_dashboard_widgets' ) ) {
/**
* Remove admin dashboard widgets for editors
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
/**
* Remove admin dashboard widgets for editors
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
function fictioneer_reduce_editor_dashboard_widgets() {
global $wp_meta_boxes;
function fictioneer_reduce_editor_dashboard_widgets() {
global $wp_meta_boxes;
// Keep
$right_now = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'];
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Keep
$right_now = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'];
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'] = $right_now;
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'] = $right_now;
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
if ( ! function_exists( 'fictioneer_hide_editor_comments_utilities' ) ) {
/**
* Hide comments utilities in admin dashboard for editors
*
* @since Fictioneer 5.0
*/
/**
* Hide comments utilities in admin dashboard for editors
*
* @since Fictioneer 5.0
*/
function fictioneer_hide_editor_comments_utilities() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('.dashboard-comment-wrap > .row-actions').remove();
$('#latest-comments > .subsubsub').remove();
$('#dashboard_right_now .comment-count').remove();
});"
);
}
function fictioneer_hide_editor_comments_utilities() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('.dashboard-comment-wrap > .row-actions').remove();
$('#latest-comments > .subsubsub').remove();
$('#dashboard_right_now .comment-count').remove();
});"
);
}
// Apply restrictions to editors
@ -306,69 +282,63 @@ if (
// RESTRICT CONTRIBUTOR ROLE
// =============================================================================
if ( ! function_exists( 'fictioneer_reduce_contributor_dashboard_widgets' ) ) {
/**
* Remove admin dashboard widgets for contributors
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
/**
* Remove admin dashboard widgets for contributors
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
function fictioneer_reduce_contributor_dashboard_widgets() {
global $wp_meta_boxes;
function fictioneer_reduce_contributor_dashboard_widgets() {
global $wp_meta_boxes;
// Keep
$right_now = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'];
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Keep
$right_now = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'];
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'] = $right_now;
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'] = $right_now;
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
if ( ! function_exists( 'fictioneer_reduce_contributor_admin_bar' ) ) {
/**
* Remove items from admin bar for contributors
*
* @since Fictioneer 5.0
*/
/**
* Remove items from admin bar for contributors
*
* @since Fictioneer 5.0
*/
function fictioneer_reduce_contributor_admin_bar() {
global $wp_admin_bar;
function fictioneer_reduce_contributor_admin_bar() {
global $wp_admin_bar;
// Remove all [+New] items
$wp_admin_bar->remove_node( 'new-content' );
// Remove all [+New] items
$wp_admin_bar->remove_node( 'new-content' );
// Remove comments
$wp_admin_bar->remove_node( 'comments' );
}
// Remove comments
$wp_admin_bar->remove_node( 'comments' );
}
if ( ! function_exists( 'fictioneer_hide_contributor_comments_utilities' ) ) {
/**
* Hide comments utilities in admin dashboard for contributors
*
* @since Fictioneer 5.0
*/
/**
* Hide comments utilities in admin dashboard for contributors
*
* @since Fictioneer 5.0
*/
function fictioneer_hide_contributor_comments_utilities() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('.dashboard-comment-wrap > .row-actions').remove();
$('#latest-comments > .subsubsub').remove();
$('#dashboard_right_now .comment-count').remove();
});"
);
}
function fictioneer_hide_contributor_comments_utilities() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('.dashboard-comment-wrap > .row-actions').remove();
$('#latest-comments > .subsubsub').remove();
$('#dashboard_right_now .comment-count').remove();
});"
);
}
// Apply restrictions to editors
@ -385,66 +355,60 @@ if (
// RESTRICT AUTHOR ROLE
// =============================================================================
if ( ! function_exists( 'fictioneer_reduce_author_dashboard_widgets' ) ) {
/**
* Remove admin dashboard widgets for authors
*
* @since Fictioneer 5.5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
/**
* Remove admin dashboard widgets for authors
*
* @since Fictioneer 5.5.0
* @link https://developer.wordpress.org/apis/handbook/dashboard-widgets/
*/
function fictioneer_reduce_author_dashboard_widgets() {
global $wp_meta_boxes;
function fictioneer_reduce_author_dashboard_widgets() {
global $wp_meta_boxes;
// Keep
$right_now = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'];
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Keep
$right_now = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'];
$activity = $wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Remove all
$wp_meta_boxes['dashboard']['normal']['core'] = [];
$wp_meta_boxes['dashboard']['side']['core'] = [];
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'] = $right_now;
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Re-add kept widgets
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now'] = $right_now;
$wp_meta_boxes['dashboard']['normal']['core']['dashboard_activity'] = $activity;
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
// Remove actions
remove_action( 'welcome_panel', 'wp_welcome_panel' );
}
if ( ! function_exists( 'fictioneer_reduce_author_admin_bar' ) ) {
/**
* Remove items from admin bar for authors
*
* @since Fictioneer 5.5.0
*/
/**
* Remove items from admin bar for authors
*
* @since Fictioneer 5.5.0
*/
function fictioneer_reduce_author_admin_bar() {
global $wp_admin_bar;
function fictioneer_reduce_author_admin_bar() {
global $wp_admin_bar;
// Remove comments
$wp_admin_bar->remove_node( 'comments' );
}
// Remove comments
$wp_admin_bar->remove_node( 'comments' );
}
if ( ! function_exists( 'fictioneer_hide_author_comments_utilities' ) ) {
/**
* Hide comments utilities in admin dashboard for authors
*
* @since Fictioneer 5.5.0
*/
/**
* Hide comments utilities in admin dashboard for authors
*
* @since Fictioneer 5.5.0
*/
function fictioneer_hide_author_comments_utilities() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('.dashboard-comment-wrap > .row-actions').remove();
$('#latest-comments > .subsubsub').remove();
$('#dashboard_right_now .comment-count').remove();
});"
);
}
function fictioneer_hide_author_comments_utilities() {
wp_add_inline_script(
'fictioneer-admin-script',
"jQuery(function($) {
$('.dashboard-comment-wrap > .row-actions').remove();
$('#latest-comments > .subsubsub').remove();
$('#dashboard_right_now .comment-count').remove();
});"
);
}
// Apply restrictions to authors

View File

@ -307,63 +307,61 @@ if ( ! function_exists( 'fictioneer_get_schema_node_list' ) ) {
// OUTPUT SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_output_schemas' ) ) {
/**
* Output schema graph on selected pages
*
* @since Fictioneer 5.0
*
* @param int|null $post_id Optional. The current post ID.
*/
/**
* Output schema graph on selected pages
*
* @since Fictioneer 5.0
*
* @param int|null $post_id Optional. The current post ID.
*/
function fictioneer_output_schemas( $post_id = null ) {
// Setup
$post_id = $post_id ? $post_id : get_queried_object_id(); // In archives, this is the first post
$schema = get_post_meta( $post_id, 'fictioneer_schema', true ); // Cached schema
$skip = is_archive() || is_search() || is_home() || is_front_page();
function fictioneer_output_schemas( $post_id = null ) {
// Setup
$post_id = $post_id ? $post_id : get_queried_object_id(); // In archives, this is the first post
$schema = get_post_meta( $post_id, 'fictioneer_schema', true ); // Cached schema
$skip = is_archive() || is_search() || is_home() || is_front_page();
// No schema found...
if ( ! $schema && ! $skip ) {
// Look at template first...
switch ( get_page_template_slug() ) {
case 'chapters.php':
$schema = fictioneer_build_chapters_schema( $post_id );
break;
case 'stories.php':
$schema = fictioneer_build_stories_schema( $post_id );
break;
case 'recommendations.php':
$schema = fictioneer_build_recommendations_schema( $post_id );
break;
case 'collections.php':
$schema = fictioneer_build_collections_schema( $post_id );
break;
}
// Look at post type if still no schema...
if ( ! $schema ) {
switch ( get_post_type() ) {
case 'post':
$schema = fictioneer_build_post_schema( $post_id );
break;
case 'fcn_story':
$schema = fictioneer_build_story_schema( $post_id );
break;
case 'fcn_chapter':
$schema = fictioneer_build_chapter_schema( $post_id );
break;
case 'fcn_recommendation':
$schema = fictioneer_build_recommendation_schema( $post_id );
break;
}
}
// No schema found...
if ( ! $schema && ! $skip ) {
// Look at template first...
switch ( get_page_template_slug() ) {
case 'chapters.php':
$schema = fictioneer_build_chapters_schema( $post_id );
break;
case 'stories.php':
$schema = fictioneer_build_stories_schema( $post_id );
break;
case 'recommendations.php':
$schema = fictioneer_build_recommendations_schema( $post_id );
break;
case 'collections.php':
$schema = fictioneer_build_collections_schema( $post_id );
break;
}
// If schema has been found, echo for selected post types
if ( $schema && ! $skip ) {
echo $schema ? '<script type="application/ld+json">' . $schema . '</script>' : '';
// Look at post type if still no schema...
if ( ! $schema ) {
switch ( get_post_type() ) {
case 'post':
$schema = fictioneer_build_post_schema( $post_id );
break;
case 'fcn_story':
$schema = fictioneer_build_story_schema( $post_id );
break;
case 'fcn_chapter':
$schema = fictioneer_build_chapter_schema( $post_id );
break;
case 'fcn_recommendation':
$schema = fictioneer_build_recommendation_schema( $post_id );
break;
}
}
}
// If schema has been found, echo for selected post types
if ( $schema && ! $skip ) {
echo $schema ? '<script type="application/ld+json">' . $schema . '</script>' : '';
}
}
if ( get_option( 'fictioneer_enable_seo' ) && ! fictioneer_seo_plugin_active() ) {

View File

@ -4,32 +4,30 @@
// ADD SEO METABOX
// =============================================================================
if ( ! function_exists( 'fictioneer_add_seo_metabox' ) ) {
/**
* Adds a SEO metabox to selected post types
*
* @since Fictioneer 4.0
*
* @param string $post_type Post type.
* @param string $post Post object.
*/
/**
* Adds a SEO metabox to selected post types
*
* @since Fictioneer 4.0
*
* @param string $post_type Post type.
* @param string $post Post object.
*/
function fictioneer_add_seo_metabox( $post_type, $post ) {
// Setup
$for_these_types = ['post', 'page', 'fcn_story', 'fcn_chapter', 'fcn_collection', 'fcn_recommendation'];
$not_these_slugs = ['singular-bookshelf.php', 'singular-bookmarks.php', 'user-profile.php'];
function fictioneer_add_seo_metabox( $post_type, $post ) {
// Setup
$for_these_types = ['post', 'page', 'fcn_story', 'fcn_chapter', 'fcn_collection', 'fcn_recommendation'];
$not_these_slugs = ['singular-bookshelf.php', 'singular-bookmarks.php', 'user-profile.php'];
// Add meta box
if ( in_array( $post_type, $for_these_types ) && ! in_array( get_page_template_slug( $post ), $not_these_slugs ) ) {
add_meta_box(
'fictioneer-search-engine-appearance',
__( 'SEO & Meta Tags', 'fictioneer' ),
'fictioneer_seo_fields',
null,
'normal',
'high'
);
}
// Add meta box
if ( in_array( $post_type, $for_these_types ) && ! in_array( get_page_template_slug( $post ), $not_these_slugs ) ) {
add_meta_box(
'fictioneer-search-engine-appearance',
__( 'SEO & Meta Tags', 'fictioneer' ),
'fictioneer_seo_fields',
null,
'normal',
'high'
);
}
}
@ -147,48 +145,46 @@ if ( ! function_exists( 'fictioneer_seo_fields' ) ) {
// SAVE SEO METABOX
// =============================================================================
if ( ! function_exists( 'fictioneer_save_seo_metabox' ) ) {
/**
* Save SEO metabox data
*
* @since Fictioneer 4.0
*
* @param int $post_id The post ID.
*/
/**
* Save SEO metabox data
*
* @since Fictioneer 4.0
*
* @param int $post_id The post ID.
*/
function fictioneer_save_seo_metabox( $post_id ) {
// Validations
if (
! isset( $_POST['fictioneer_metabox_seo_nonce'] ) ||
! wp_verify_nonce( $_POST['fictioneer_metabox_seo_nonce'], 'fictioneer-metabox-seo-save' ) ||
! current_user_can( 'edit_post', $post_id ) ||
wp_is_post_autosave( $post_id ) ||
wp_is_post_revision( $post_id ) ||
in_array( get_post_status( $post_id ), ['auto-draft'] )
) {
return;
}
// Save image
if ( isset( $_POST['fictioneer_seo_og_image'] ) ) {
update_post_meta( $post_id, 'fictioneer_seo_og_image', $_POST['fictioneer_seo_og_image'] );
}
// Save title
if ( isset( $_POST['fictioneer_seo_title'] ) ) {
update_post_meta( $post_id, 'fictioneer_seo_title', $_POST['fictioneer_seo_title'] );
}
// Save description
if ( isset( $_POST['fictioneer_seo_description'] ) ) {
update_post_meta( $post_id, 'fictioneer_seo_description', $_POST['fictioneer_seo_description'] );
}
// Clear caches
delete_post_meta( $post_id, 'fictioneer_seo_title_cache' );
delete_post_meta( $post_id, 'fictioneer_seo_description_cache' );
delete_post_meta( $post_id, 'fictioneer_seo_og_image_cache' );
function fictioneer_save_seo_metabox( $post_id ) {
// Validations
if (
! isset( $_POST['fictioneer_metabox_seo_nonce'] ) ||
! wp_verify_nonce( $_POST['fictioneer_metabox_seo_nonce'], 'fictioneer-metabox-seo-save' ) ||
! current_user_can( 'edit_post', $post_id ) ||
wp_is_post_autosave( $post_id ) ||
wp_is_post_revision( $post_id ) ||
in_array( get_post_status( $post_id ), ['auto-draft'] )
) {
return;
}
// Save image
if ( isset( $_POST['fictioneer_seo_og_image'] ) ) {
update_post_meta( $post_id, 'fictioneer_seo_og_image', $_POST['fictioneer_seo_og_image'] );
}
// Save title
if ( isset( $_POST['fictioneer_seo_title'] ) ) {
update_post_meta( $post_id, 'fictioneer_seo_title', $_POST['fictioneer_seo_title'] );
}
// Save description
if ( isset( $_POST['fictioneer_seo_description'] ) ) {
update_post_meta( $post_id, 'fictioneer_seo_description', $_POST['fictioneer_seo_description'] );
}
// Clear caches
delete_post_meta( $post_id, 'fictioneer_seo_title_cache' );
delete_post_meta( $post_id, 'fictioneer_seo_description_cache' );
delete_post_meta( $post_id, 'fictioneer_seo_og_image_cache' );
}
if ( get_option( 'fictioneer_enable_seo' ) && ! fictioneer_seo_plugin_active() ) {
@ -617,120 +613,118 @@ if ( ! function_exists( 'fictioneer_get_seo_image' ) ) {
// OUTPUT HEAD SEO
// =============================================================================
if ( ! function_exists( 'fictioneer_output_head_seo' ) ) {
/**
* Output HTML <head> SEO meta
*
* @since Fictioneer 5.0
*/
/**
* Output HTML <head> SEO meta
*
* @since Fictioneer 5.0
*/
function fictioneer_output_head_seo() {
global $wp;
global $post;
function fictioneer_output_head_seo() {
global $wp;
global $post;
// Setup
$post_id = get_queried_object_id(); // In archives and search, this is the first post
$post_type = get_post_type(); // In archives and search, this is the first post
$post_author = $post->post_author ?? 0;
$chapter_story_id = fictioneer_get_field( 'fictioneer_chapter_story' ) ?? 0;
$canonical_url = wp_get_canonical_url(); // Unreliable on aggregated pages
// Setup
$post_id = get_queried_object_id(); // In archives and search, this is the first post
$post_type = get_post_type(); // In archives and search, this is the first post
$post_author = $post->post_author ?? 0;
$chapter_story_id = fictioneer_get_field( 'fictioneer_chapter_story' ) ?? 0;
$canonical_url = wp_get_canonical_url(); // Unreliable on aggregated pages
// Flags
$is_page = is_page() || is_front_page() || is_home();
$is_aggregated = is_archive() || is_search();
$is_article = ! $is_page && in_array( $post_type, ['fcn_story', 'fcn_chapter', 'fcn_recommendation', 'post'] );
$show_author = $is_article && is_single() && ! is_front_page() && ! is_home() && ! $is_aggregated;
// Flags
$is_page = is_page() || is_front_page() || is_home();
$is_aggregated = is_archive() || is_search();
$is_article = ! $is_page && in_array( $post_type, ['fcn_story', 'fcn_chapter', 'fcn_recommendation', 'post'] );
$show_author = $is_article && is_single() && ! is_front_page() && ! is_home() && ! $is_aggregated;
// Derived
$og_type = $is_article ? 'article' : 'website';
$og_image = fictioneer_get_seo_image( $post_id );
$og_title = fictioneer_get_seo_title( $post_id );
$og_description = fictioneer_get_seo_description( $post_id );
$article_author = $post_author && $show_author ? get_the_author_meta( 'display_name', $post_author ) : false;
$article_twitter = $post_author && $show_author ? get_the_author_meta( 'twitter', $post_author ) : false;
// Derived
$og_type = $is_article ? 'article' : 'website';
$og_image = fictioneer_get_seo_image( $post_id );
$og_title = fictioneer_get_seo_title( $post_id );
$og_description = fictioneer_get_seo_description( $post_id );
$article_author = $post_author && $show_author ? get_the_author_meta( 'display_name', $post_author ) : false;
$article_twitter = $post_author && $show_author ? get_the_author_meta( 'twitter', $post_author ) : false;
// Special Case: Recommendation author
if ( $post_author && $show_author && $post_type == 'fcn_recommendation' ) {
$article_author = fictioneer_get_field( 'fictioneer_recommendation_author', $post_id ) ?? $article_author;
}
// Special Case: Archives
if ( is_archive() ) $canonical_url = home_url( $wp->request );
// Special Case: Search
if ( is_search() ) $canonical_url = add_query_arg( 's', '', home_url( $wp->request ) );
// Start HTML ---> ?>
<link rel="canonical" href="<?php echo $canonical_url; ?>">
<meta name="description" content="<?php echo $og_description; ?>">
<meta property="og:locale" content="<?php echo get_locale(); ?>">
<meta property="og:type" content="<?php echo $og_type; ?>">
<meta property="og:title" content="<?php echo $og_title; ?>">
<meta property="og:description" content="<?php echo $og_description; ?>">
<meta property="og:url" content="<?php echo $canonical_url; ?>">
<meta property="og:site_name" content="<?php echo FICTIONEER_SITE_NAME; ?>">
<?php if ( ! $is_aggregated && $is_article ) : ?>
<meta property="article:published_time" content="<?php echo get_the_date( 'c' ); ?>">
<meta property="article:modified_time" content="<?php echo get_the_modified_date( 'c' ); ?>">
<?php if ( $show_author && $article_author ) : ?>
<?php
// Get URL for primary author (if any)
$article_author_url = get_the_author_meta( 'url', $post_author );
$article_author_url = empty( $article_author_url ) ? get_author_posts_url( $post_author ) : $article_author_url;
// Prepare author array with either URL (required) or name (better than nothing)
$all_authors = empty( $article_author_url ) ? [$article_author] : [$article_author_url];
// Get co-authors (if any)
$co_authors = $post_type == 'fcn_story' ?
fictioneer_get_field( 'fictioneer_story_co_authors', $post_id ) ?? [] :
fictioneer_get_field( 'fictioneer_chapter_co_authors', $post_id ) ?? [];
// Add co-authors URL or name
if ( ! empty( $co_authors ) ) {
foreach ( $co_authors as $co_author_id ) {
$co_author_name = get_the_author_meta( 'display_name', intval( $co_author_id ) );
$co_author_url = get_the_author_meta( 'url', intval( $co_author_id ) );
$co_author_url = empty( $co_author_url ) ? get_author_posts_url( $co_author_id ) : $co_author_url;
$author_item = empty( $co_author_url ) ? $co_author_name : $co_author_url;
if ( ! empty( $author_item ) && ! in_array( $author_item, $all_authors ) ) $all_authors[] = $author_item;
}
}
// Output og array
foreach ( $all_authors as $author_name ) {
echo "<meta property='article:author' content='$author_name'>";
}
?>
<?php endif; ?>
<?php if ( $post_type == 'fcn_chapter' && ! empty( $chapter_story_id ) ) : ?>
<meta property="article:section" content="<?php echo get_the_title( $chapter_story_id ); ?>">
<?php endif; ?>
<?php endif; ?>
<?php if ( is_array( $og_image ) && count( $og_image ) >= 4 ) : ?>
<meta property="og:image" content="<?php echo $og_image['url']; ?>">
<meta property="og:image:width" content="<?php echo $og_image['width']; ?>">
<meta property="og:image:height" content="<?php echo $og_image['height']; ?>">
<meta property="og:image:type" content="<?php echo $og_image['type']; ?>">
<meta name="twitter:image" content="<?php echo $og_image['url']; ?>">
<?php endif; ?>
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="<?php echo $og_title; ?>">
<meta name="twitter:description" content="<?php echo $og_description; ?>">
<?php if ( $show_author && $article_twitter ) : ?>
<meta name="twitter:creator" content="<?php echo '@' . $article_twitter; ?>">
<meta name="twitter:site" content="<?php echo '@' . $article_twitter; ?>">
<?php endif; ?>
<?php // <--- End HTML
// Special Case: Recommendation author
if ( $post_author && $show_author && $post_type == 'fcn_recommendation' ) {
$article_author = fictioneer_get_field( 'fictioneer_recommendation_author', $post_id ) ?? $article_author;
}
// Special Case: Archives
if ( is_archive() ) $canonical_url = home_url( $wp->request );
// Special Case: Search
if ( is_search() ) $canonical_url = add_query_arg( 's', '', home_url( $wp->request ) );
// Start HTML ---> ?>
<link rel="canonical" href="<?php echo $canonical_url; ?>">
<meta name="description" content="<?php echo $og_description; ?>">
<meta property="og:locale" content="<?php echo get_locale(); ?>">
<meta property="og:type" content="<?php echo $og_type; ?>">
<meta property="og:title" content="<?php echo $og_title; ?>">
<meta property="og:description" content="<?php echo $og_description; ?>">
<meta property="og:url" content="<?php echo $canonical_url; ?>">
<meta property="og:site_name" content="<?php echo FICTIONEER_SITE_NAME; ?>">
<?php if ( ! $is_aggregated && $is_article ) : ?>
<meta property="article:published_time" content="<?php echo get_the_date( 'c' ); ?>">
<meta property="article:modified_time" content="<?php echo get_the_modified_date( 'c' ); ?>">
<?php if ( $show_author && $article_author ) : ?>
<?php
// Get URL for primary author (if any)
$article_author_url = get_the_author_meta( 'url', $post_author );
$article_author_url = empty( $article_author_url ) ? get_author_posts_url( $post_author ) : $article_author_url;
// Prepare author array with either URL (required) or name (better than nothing)
$all_authors = empty( $article_author_url ) ? [$article_author] : [$article_author_url];
// Get co-authors (if any)
$co_authors = $post_type == 'fcn_story' ?
fictioneer_get_field( 'fictioneer_story_co_authors', $post_id ) ?? [] :
fictioneer_get_field( 'fictioneer_chapter_co_authors', $post_id ) ?? [];
// Add co-authors URL or name
if ( ! empty( $co_authors ) ) {
foreach ( $co_authors as $co_author_id ) {
$co_author_name = get_the_author_meta( 'display_name', intval( $co_author_id ) );
$co_author_url = get_the_author_meta( 'url', intval( $co_author_id ) );
$co_author_url = empty( $co_author_url ) ? get_author_posts_url( $co_author_id ) : $co_author_url;
$author_item = empty( $co_author_url ) ? $co_author_name : $co_author_url;
if ( ! empty( $author_item ) && ! in_array( $author_item, $all_authors ) ) $all_authors[] = $author_item;
}
}
// Output og array
foreach ( $all_authors as $author_name ) {
echo "<meta property='article:author' content='$author_name'>";
}
?>
<?php endif; ?>
<?php if ( $post_type == 'fcn_chapter' && ! empty( $chapter_story_id ) ) : ?>
<meta property="article:section" content="<?php echo get_the_title( $chapter_story_id ); ?>">
<?php endif; ?>
<?php endif; ?>
<?php if ( is_array( $og_image ) && count( $og_image ) >= 4 ) : ?>
<meta property="og:image" content="<?php echo $og_image['url']; ?>">
<meta property="og:image:width" content="<?php echo $og_image['width']; ?>">
<meta property="og:image:height" content="<?php echo $og_image['height']; ?>">
<meta property="og:image:type" content="<?php echo $og_image['type']; ?>">
<meta name="twitter:image" content="<?php echo $og_image['url']; ?>">
<?php endif; ?>
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="<?php echo $og_title; ?>">
<meta name="twitter:description" content="<?php echo $og_description; ?>">
<?php if ( $show_author && $article_twitter ) : ?>
<meta name="twitter:creator" content="<?php echo '@' . $article_twitter; ?>">
<meta name="twitter:site" content="<?php echo '@' . $article_twitter; ?>">
<?php endif; ?>
<?php // <--- End HTML
}
if ( get_option( 'fictioneer_enable_seo' ) && ! fictioneer_seo_plugin_active() ) {

View File

@ -70,180 +70,178 @@ function fictioneer_url_node( $loc, $lastmod = null, $freq = null ) {
return $node;
}
if ( ! function_exists( 'fictioneer_create_sitemap' ) ) {
function fictioneer_create_sitemap( $last_saved_id ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $last_saved_id ) ) {
return;
function fictioneer_create_sitemap( $last_saved_id ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $last_saved_id ) ) {
return;
}
// Only rebuild necessary part of the sitemap
$last_saved_type = get_post_type( $last_saved_id );
// Only consider these post types
$allowed_types = ['page', 'post', 'fcn_story', 'fcn_chapter', 'fcn_recommendation', 'fcn_collection'];
if ( in_array( $last_saved_type, $allowed_types ) ) {
// Open
$sitemap = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$sitemap .= '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
// Blog and front page
$sitemap .= fictioneer_url_node( esc_url( home_url( '/' ) ), current_time( 'c' ), 'daily' );
$sitemap .= fictioneer_url_node( get_permalink( get_option( 'page_for_posts' ) ), current_time( 'c' ), 'daily' );
// Pages
$pages = $last_saved_type == 'page' ? false : get_transient( 'fictioneer_sitemap_pages' );
if ( ! $pages ) {
$pages = get_posts( array(
'post_type' => 'page',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000',
'post__not_in' => [get_option( 'page_on_front' ), get_option( 'page_for_posts' )]
));
set_transient( 'fictioneer_sitemap_pages', $pages );
}
// Only rebuild necessary part of the sitemap
$last_saved_type = get_post_type( $last_saved_id );
foreach( $pages as $post ) {
$template = get_page_template_slug( $post->ID );
if ( in_array( $template, ['user-profile.php', 'single-bookmarks.php'] ) ) continue;
$frequency = 'yearly';
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'yearly' );
}
// Only consider these post types
$allowed_types = ['page', 'post', 'fcn_story', 'fcn_chapter', 'fcn_recommendation', 'fcn_collection'];
// Blogposts
$blogposts = $last_saved_type == 'post' ? false : get_transient( 'fictioneer_sitemap_posts' );
if ( in_array( $last_saved_type, $allowed_types ) ) {
// Open
$sitemap = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$sitemap .= '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
if ( ! $blogposts ) {
$blogposts = get_posts( array(
'post_type' => 'post',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000'
));
set_transient( 'fictioneer_sitemap_posts', $blogposts );
}
// Blog and front page
$sitemap .= fictioneer_url_node( esc_url( home_url( '/' ) ), current_time( 'c' ), 'daily' );
$sitemap .= fictioneer_url_node( get_permalink( get_option( 'page_for_posts' ) ), current_time( 'c' ), 'daily' );
foreach( $blogposts as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'never' );
}
// Pages
$pages = $last_saved_type == 'page' ? false : get_transient( 'fictioneer_sitemap_pages' );
// Collections
$collections = $last_saved_type == 'fcn_collection' ? false : get_transient( 'fictioneer_sitemap_collections' );
if ( ! $pages ) {
$pages = get_posts( array(
'post_type' => 'page',
if ( ! $collections ) {
$collections = get_posts( array(
'post_type' => 'fcn_collection',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000'
));
set_transient( 'fictioneer_sitemap_collections', $collections );
}
foreach( $collections as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'monthly' );
}
// Stories
$stories = $last_saved_type == 'fcn_story' ? false : get_transient( 'fictioneer_sitemap_stories' );
if ( ! $stories ) {
$stories = get_posts(
array(
'post_type' => 'fcn_story',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000',
'post__not_in' => [get_option( 'page_on_front' ), get_option( 'page_for_posts' )]
));
set_transient( 'fictioneer_sitemap_pages', $pages );
}
foreach( $pages as $post ) {
$template = get_page_template_slug( $post->ID );
if ( in_array( $template, ['user-profile.php', 'single-bookmarks.php'] ) ) continue;
$frequency = 'yearly';
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'yearly' );
}
// Blogposts
$blogposts = $last_saved_type == 'post' ? false : get_transient( 'fictioneer_sitemap_posts' );
if ( ! $blogposts ) {
$blogposts = get_posts( array(
'post_type' => 'post',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000'
));
set_transient( 'fictioneer_sitemap_posts', $blogposts );
}
foreach( $blogposts as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'never' );
}
// Collections
$collections = $last_saved_type == 'fcn_collection' ? false : get_transient( 'fictioneer_sitemap_collections' );
if ( ! $collections ) {
$collections = get_posts( array(
'post_type' => 'fcn_collection',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000'
));
set_transient( 'fictioneer_sitemap_collections', $collections );
}
foreach( $collections as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'monthly' );
}
// Stories
$stories = $last_saved_type == 'fcn_story' ? false : get_transient( 'fictioneer_sitemap_stories' );
if ( ! $stories ) {
$stories = get_posts(
array(
'post_type' => 'fcn_story',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '2000',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'fictioneer_story_hidden',
'value' => '0'
),
array(
'key' => 'fictioneer_story_hidden',
'compare' => 'NOT EXISTS'
)
'numberposts' => '2000',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'fictioneer_story_hidden',
'value' => '0'
),
array(
'key' => 'fictioneer_story_hidden',
'compare' => 'NOT EXISTS'
)
)
);
set_transient( 'fictioneer_sitemap_stories', $stories );
}
foreach ( $stories as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$status = fictioneer_get_field( 'fictioneer_story_status', $post->ID );
$frequency = $status == 'Ongoing' ? 'weekly' : 'monthly';
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, $frequency );
}
// Chapters
$chapters = $last_saved_type == 'fcn_chapter' ? false : get_transient( 'fictioneer_sitemap_chapters' );
if ( ! $chapters ) {
$chapters = get_posts( array(
'post_type' => 'fcn_chapter',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '10000',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'fictioneer_chapter_hidden',
'value' => '0'
),
array(
'key' => 'fictioneer_chapter_hidden',
'compare' => 'NOT EXISTS'
)
)
));
set_transient( 'fictioneer_sitemap_chapters', $chapters );
}
foreach( $chapters as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'monthly' );
}
// Recommendations
$recommendations = $last_saved_type == 'fcn_recommendation' ? false : get_transient( 'fictioneer_sitemap_recommendations' );
if ( ! $recommendations ) {
$recommendations = get_posts( array(
'post_type' => 'fcn_recommendation',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000'
));
set_transient( 'fictioneer_sitemap_recommendations', $recommendations );
}
foreach( $recommendations as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'yearly' );
}
// End
$sitemap .= "\n" . '</urlset>';
// Save
$file_path = fopen( ABSPATH . '/sitemap.xml', 'w' );
fwrite( $file_path, $sitemap );
fclose( $file_path );
)
);
set_transient( 'fictioneer_sitemap_stories', $stories );
}
foreach ( $stories as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$status = fictioneer_get_field( 'fictioneer_story_status', $post->ID );
$frequency = $status == 'Ongoing' ? 'weekly' : 'monthly';
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, $frequency );
}
// Chapters
$chapters = $last_saved_type == 'fcn_chapter' ? false : get_transient( 'fictioneer_sitemap_chapters' );
if ( ! $chapters ) {
$chapters = get_posts( array(
'post_type' => 'fcn_chapter',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '10000',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'fictioneer_chapter_hidden',
'value' => '0'
),
array(
'key' => 'fictioneer_chapter_hidden',
'compare' => 'NOT EXISTS'
)
)
));
set_transient( 'fictioneer_sitemap_chapters', $chapters );
}
foreach( $chapters as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'monthly' );
}
// Recommendations
$recommendations = $last_saved_type == 'fcn_recommendation' ? false : get_transient( 'fictioneer_sitemap_recommendations' );
if ( ! $recommendations ) {
$recommendations = get_posts( array(
'post_type' => 'fcn_recommendation',
'post_status' => array( 'publish' ),
'orderby' => 'date',
'order' => 'DESC',
'numberposts' => '1000'
));
set_transient( 'fictioneer_sitemap_recommendations', $recommendations );
}
foreach( $recommendations as $post ) {
$lastmod = get_the_modified_date( 'c', $post->ID );
$sitemap .= fictioneer_url_node( get_permalink( $post->ID ), $lastmod, 'yearly' );
}
// End
$sitemap .= "\n" . '</urlset>';
// Save
$file_path = fopen( ABSPATH . '/sitemap.xml', 'w' );
fwrite( $file_path, $sitemap );
fclose( $file_path );
}
}

View File

@ -363,15 +363,15 @@ add_action( 'get_footer', 'fictioneer_style_footer_queue' );
// FONT AWESOME 6+
// =============================================================================
/**
* Add Font Awesome 6+ to the site
*
* @since 4.5
* @link https://fontawesome.com/docs/web/use-with/wordpress/install-manually
* @link https://fontawesome.com/account/cdn
*/
if ( ! function_exists( 'fa_custom_setup_cdn_webfont' ) ) {
/**
* Add Font Awesome 6+ to the site
*
* @since 4.5
* @link https://fontawesome.com/docs/web/use-with/wordpress/install-manually
* @link https://fontawesome.com/account/cdn
*/
function fa_custom_setup_cdn_webfont( $cdn_url = '', $integrity = null ) {
$matches = [];
$match_result = preg_match( '|/([^/]+?)\.css$|', $cdn_url, $matches );

View File

@ -4,20 +4,18 @@
// MAINTENANCE MODE
// =============================================================================
if ( ! function_exists( 'fictioneer_maintenance_mode' ) ) {
/**
* Toggle maintenance mode from settings with message
*
* @since 5.0
*/
/**
* Toggle maintenance mode from settings with message
*
* @since 5.0
*/
function fictioneer_maintenance_mode() {
if ( get_option( 'fictioneer_enable_maintenance_mode' ) ) {
if ( ! current_user_can( 'edit_themes' ) || ! is_user_logged_in() ) {
$note = get_option( 'fictioneer_phrase_maintenance' );
$note = ! empty( $note ) ? $note : __( 'Website under planned maintenance. Please check back later.', 'fictioneer' );
wp_die( __( '<h1>Under Maintenance</h1><br>', 'fictioneer' ) . $note );
}
function fictioneer_maintenance_mode() {
if ( get_option( 'fictioneer_enable_maintenance_mode' ) ) {
if ( ! current_user_can( 'edit_themes' ) || ! is_user_logged_in() ) {
$note = get_option( 'fictioneer_phrase_maintenance' );
$note = ! empty( $note ) ? $note : __( 'Website under planned maintenance. Please check back later.', 'fictioneer' );
wp_die( __( '<h1>Under Maintenance</h1><br>', 'fictioneer' ) . $note );
}
}
}
@ -56,14 +54,12 @@ if ( get_option( 'fictioneer_enable_sitemap' ) && ! fictioneer_seo_plugin_active
// CUSTOM EXCERPT LENGTH
// =============================================================================
if ( ! function_exists( 'fictioneer_custom_excerpt_length' ) ) {
/**
* Change excerpt length
*/
/**
* Change excerpt length
*/
function fictioneer_custom_excerpt_length( $length ) {
return 64;
}
function fictioneer_custom_excerpt_length( $length ) {
return 64;
}
add_filter( 'excerpt_length', 'fictioneer_custom_excerpt_length', 999 );
@ -71,22 +67,20 @@ add_filter( 'excerpt_length', 'fictioneer_custom_excerpt_length', 999 );
// FIX EXCERPT FORMATTING
// =============================================================================
if ( ! function_exists( 'fictioneer_fix_excerpt' ) ) {
/**
* Fix inconsistent line breaks in excerpts
*
* @since 4.0
* @link https://github.com/WordPress/gutenberg/issues/15117
*
* @param string $excerpt The post excerpt.
*/
/**
* Fix inconsistent line breaks in excerpts
*
* @since 4.0
* @link https://github.com/WordPress/gutenberg/issues/15117
*
* @param string $excerpt The post excerpt.
*/
function fictioneer_fix_excerpt( $excerpt ) {
add_filter( 'the_content', 'fictioneer_replace_br_with_whitespace', 6 );
$excerpt = wp_trim_excerpt( $excerpt );
remove_filter( 'the_content', 'fictioneer_replace_br_with_whitespace', 6 );
return $excerpt;
}
function fictioneer_fix_excerpt( $excerpt ) {
add_filter( 'the_content', 'fictioneer_replace_br_with_whitespace', 6 );
$excerpt = wp_trim_excerpt( $excerpt );
remove_filter( 'the_content', 'fictioneer_replace_br_with_whitespace', 6 );
return $excerpt;
}
remove_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
add_filter( 'get_the_excerpt', 'fictioneer_fix_excerpt' );
@ -107,39 +101,37 @@ function fictioneer_replace_br_with_whitespace( $text ) {
// UPDATE MODIFIED DATE OF STORY WHEN CHAPTER IS UPDATED
// =============================================================================
if ( ! function_exists( 'fictioneer_update_modified_date_on_story_for_chapter' ) ) {
/**
* Update modified date of story when chapter is updated
*
* @since 3.0
*
* @param int $post_id The post ID.
*/
/**
* Update modified date of story when chapter is updated
*
* @since 3.0
*
* @param int $post_id The post ID.
*/
function fictioneer_update_modified_date_on_story_for_chapter( $post_id ) {
global $wpdb;
function fictioneer_update_modified_date_on_story_for_chapter( $post_id ) {
global $wpdb;
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Chapter updated?
if ( get_post_type( $post_id ) != 'fcn_chapter' ) return;
// Setup
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post_id );
// No linked story found
if ( empty( $story_id ) ) return;
// Get current time for update (close enough to the chapter)
$post_modified = current_time( 'mysql' );
$post_modified_gmt = current_time( 'mysql', true );
// Update database
$wpdb->query( "UPDATE $wpdb->posts SET post_modified = '{$post_modified}', post_modified_gmt = '{$post_modified_gmt}' WHERE ID = {$story_id}" );
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Chapter updated?
if ( get_post_type( $post_id ) != 'fcn_chapter' ) return;
// Setup
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post_id );
// No linked story found
if ( empty( $story_id ) ) return;
// Get current time for update (close enough to the chapter)
$post_modified = current_time( 'mysql' );
$post_modified_gmt = current_time( 'mysql', true );
// Update database
$wpdb->query( "UPDATE $wpdb->posts SET post_modified = '{$post_modified}', post_modified_gmt = '{$post_modified_gmt}' WHERE ID = {$story_id}" );
}
add_action( 'save_post', 'fictioneer_update_modified_date_on_story_for_chapter' );
add_action( 'trashed_post', 'fictioneer_update_modified_date_on_story_for_chapter' );
@ -150,33 +142,31 @@ add_action( 'untrash_post', 'fictioneer_update_modified_date_on_story_for_chapte
// STORE WORD COUNT AS CUSTOM FIELD
// =============================================================================
if ( ! function_exists( 'fictioneer_save_word_count' ) ) {
/**
* Store word count of posts as meta data
*
* @since 3.0
* @see update_post_meta()
*
* @param int $post_id Post ID.
*/
/**
* Store word count of posts as meta data
*
* @since 3.0
* @see update_post_meta()
*
* @param int $post_id Post ID.
*/
function fictioneer_save_word_count( $post_id ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Prepare
$content = get_post_field( 'post_content', $post_id );
$content = strip_shortcodes( $content );
$content = strip_tags( $content );
// Count
$word_count = str_word_count( $content );
// Remember
update_post_meta( $post_id, '_word_count', $word_count );
function fictioneer_save_word_count( $post_id ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Prepare
$content = get_post_field( 'post_content', $post_id );
$content = strip_shortcodes( $content );
$content = strip_tags( $content );
// Count
$word_count = str_word_count( $content );
// Remember
update_post_meta( $post_id, '_word_count', $word_count );
}
add_action( 'save_post', 'fictioneer_save_word_count' );
@ -212,41 +202,39 @@ if ( get_option( 'fictioneer_reduce_admin_bar' ) ) {
// LOGOUT REDIRECT
// =============================================================================
if ( ! function_exists( 'fictioneer_logout_redirect' ) ) {
/**
* Change redirect after logout
*
* @since 4.0
*
* @param string $logout_url The HTML-encoded logout URL.
* @param string $redirect Path to redirect to on logout.
*
* @return string $logout_url The updated logout URL.
*/
/**
* Change redirect after logout
*
* @since 4.0
*
* @param string $logout_url The HTML-encoded logout URL.
* @param string $redirect Path to redirect to on logout.
*
* @return string $logout_url The updated logout URL.
*/
function fictioneer_logout_redirect( $logout_url, $redirect ) {
// Setup
$args = [];
function fictioneer_logout_redirect( $logout_url, $redirect ) {
// Setup
$args = [];
// Add redirect to args
if ( empty( $redirect ) ) {
$args['redirect_to'] = urlencode( get_permalink() );
} else {
$args['redirect_to'] = urlencode( $redirect );
}
// Avoid login page
if ( is_admin() || empty( $redirect ) ) {
$args['redirect_to'] = urlencode( get_home_url() );
}
// Rebuild logout URL
$logout_url = add_query_arg( $args, site_url( 'wp-login.php?action=logout', 'login' ) );
$logout_url = wp_nonce_url( $logout_url, 'log-out' );
// Return updated logout URL
return $logout_url;
// Add redirect to args
if ( empty( $redirect ) ) {
$args['redirect_to'] = urlencode( get_permalink() );
} else {
$args['redirect_to'] = urlencode( $redirect );
}
// Avoid login page
if ( is_admin() || empty( $redirect ) ) {
$args['redirect_to'] = urlencode( get_home_url() );
}
// Rebuild logout URL
$logout_url = add_query_arg( $args, site_url( 'wp-login.php?action=logout', 'login' ) );
$logout_url = wp_nonce_url( $logout_url, 'log-out' );
// Return updated logout URL
return $logout_url;
}
if ( get_option( 'fictioneer_logout_redirects_home' ) ) {
@ -257,58 +245,54 @@ if ( get_option( 'fictioneer_logout_redirects_home' ) ) {
// CUSTOM LOGOUT
// =============================================================================
if ( ! function_exists( 'fictioneer_add_logout_endpoint' ) ) {
/**
* Add route to logout script
*
* @since Fictioneer 5.0
*/
/**
* Add route to logout script
*
* @since Fictioneer 5.0
*/
function fictioneer_add_logout_endpoint() {
add_rewrite_endpoint( FICTIONEER_LOGOUT_ENDPOINT, EP_ROOT );
}
function fictioneer_add_logout_endpoint() {
add_rewrite_endpoint( FICTIONEER_LOGOUT_ENDPOINT, EP_ROOT );
}
if ( FICTIONEER_LOGOUT_ENDPOINT && ! get_option( 'fictioneer_disable_theme_logout' ) ) {
add_action( 'init', 'fictioneer_add_logout_endpoint', 10 );
}
if ( ! function_exists( 'fictioneer_logout' ) ) {
/**
* Logout without _wpnonce and no login screen
*
* @since 5.0
*/
/**
* Logout without _wpnonce and no login screen
*
* @since 5.0
*/
function fictioneer_logout() {
global $wp;
function fictioneer_logout() {
global $wp;
// Abort if not on logout route
if ( $wp->request != FICTIONEER_LOGOUT_ENDPOINT ) return;
// Abort if not on logout route
if ( $wp->request != FICTIONEER_LOGOUT_ENDPOINT ) return;
// Redirect home if not logged-in
if ( ! is_user_logged_in() ) wp_safe_redirect( get_home_url() );
// Redirect home if not logged-in
if ( ! is_user_logged_in() ) wp_safe_redirect( get_home_url() );
// Setup
$user = wp_get_current_user();
// Setup
$user = wp_get_current_user();
// Default WP logout
wp_logout();
// Default WP logout
wp_logout();
// Redirect URL
if ( empty( $_REQUEST['redirect_to'] ) ) {
$redirect_to = get_home_url();
} else {
$redirect_to = $_REQUEST['redirect_to'];
}
// Apply default filters
$redirect_to = apply_filters( 'logout_redirect', $redirect_to, $redirect_to, $user );
// Redirect
wp_safe_redirect( $redirect_to );
exit;
// Redirect URL
if ( empty( $_REQUEST['redirect_to'] ) ) {
$redirect_to = get_home_url();
} else {
$redirect_to = $_REQUEST['redirect_to'];
}
// Apply default filters
$redirect_to = apply_filters( 'logout_redirect', $redirect_to, $redirect_to, $user );
// Redirect
wp_safe_redirect( $redirect_to );
exit;
}
if ( FICTIONEER_LOGOUT_ENDPOINT && ! get_option( 'fictioneer_disable_theme_logout' ) ) {
@ -350,21 +334,19 @@ if ( ! function_exists( 'fictioneer_get_logout_url' ) ) {
// SHOW CUSTOM POST TYPES ON TAG/CATEGORY ARCHIVES
// =============================================================================
if ( ! function_exists( 'fictioneer_extend_taxonomy_pages' ) ) {
/**
* Show custom post types in tag and category archives
*
* @since 4.0
* @link https://wordpress.stackexchange.com/a/28147/223620
*
* @param WP_Query $query The query.
*/
/**
* Show custom post types in tag and category archives
*
* @since 4.0
* @link https://wordpress.stackexchange.com/a/28147/223620
*
* @param WP_Query $query The query.
*/
function fictioneer_extend_taxonomy_pages( $query ) {
if ( ( is_tag() || is_tax( 'fcn_genre' ) || is_tax( 'fcn_fandom' ) || is_tax( 'fcn_character' ) || is_tax( 'fcn_content_warning' ) || is_category() ) && $query->is_main_query() && ! is_admin() ) {
$post_types = array( 'post', 'fcn_story', 'fcn_chapter', 'fcn_recommendation', 'fcn_collection' );
$query->set( 'post_type', $post_types );
}
function fictioneer_extend_taxonomy_pages( $query ) {
if ( ( is_tag() || is_tax( 'fcn_genre' ) || is_tax( 'fcn_fandom' ) || is_tax( 'fcn_character' ) || is_tax( 'fcn_content_warning' ) || is_category() ) && $query->is_main_query() && ! is_admin() ) {
$post_types = array( 'post', 'fcn_story', 'fcn_chapter', 'fcn_recommendation', 'fcn_collection' );
$query->set( 'post_type', $post_types );
}
}
add_filter( 'pre_get_posts', 'fictioneer_extend_taxonomy_pages' );
@ -443,62 +425,60 @@ if ( get_option( 'fictioneer_enable_theme_rss' ) ) {
// OUTPUT RSS
// =============================================================================
if ( ! function_exists( 'fictioneer_output_rss' ) ) {
/**
* Output RSS feed
*
* @since Fictioneer 5.0
*
* @param int|null $post_id Optional. The current post ID.
*/
/**
* Output RSS feed
*
* @since Fictioneer 5.0
*
* @param int|null $post_id Optional. The current post ID.
*/
function fictioneer_output_rss( $post_id = null ) {
// Setup
$post_id = $post_id ? $post_id : get_queried_object_id(); // In archives, this is the first post
$post_type = get_post_type(); // In archives, this is the first post
$rss_link = '';
$skip_to_default = is_archive() || is_search() || post_password_required( $post_id );
function fictioneer_output_rss( $post_id = null ) {
// Setup
$post_id = $post_id ? $post_id : get_queried_object_id(); // In archives, this is the first post
$post_type = get_post_type(); // In archives, this is the first post
$rss_link = '';
$skip_to_default = is_archive() || is_search() || post_password_required( $post_id );
// RSS Feed if story...
if ( $post_type == 'fcn_story' && ! $skip_to_default ) {
$title = sprintf(
_x( '%1$s - %2$s Chapters', 'Story Feed: [Site] - [Story] Chapters.', 'fictioneer' ),
FICTIONEER_SITE_NAME,
get_the_title( get_the_ID() )
);
// RSS Feed if story...
if ( $post_type == 'fcn_story' && ! $skip_to_default ) {
$title = sprintf(
_x( '%1$s - %2$s Chapters', 'Story Feed: [Site] - [Story] Chapters.', 'fictioneer' ),
FICTIONEER_SITE_NAME,
get_the_title( get_the_ID() )
);
$url = esc_url( add_query_arg( 'story_id', get_the_ID(), home_url( 'feed/rss-chapters' ) ) );
$rss_link = '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $url . '" />';
}
// RSS Feed if chapter...
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post_id );
if ( $post_type == 'fcn_chapter' && ! empty( $story_id ) && ! $skip_to_default ) {
$title = sprintf(
_x( '%1$s - %2$s Chapters', 'Story Feed: [Site] - [Story] Chapters.', 'fictioneer' ),
FICTIONEER_SITE_NAME,
get_the_title( $story_id )
);
$url = esc_url( add_query_arg( 'story_id', $story_id, home_url( 'feed/rss-chapters' ) ) );
$rss_link = '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $url . '" />';
}
// Default RSS Feed
if ( empty( $rss_link ) ) {
$title = sprintf(
_x( '%s Feed', '[Site] Feed', 'fictioneer' ),
FICTIONEER_SITE_NAME
);
$url = esc_url( home_url( 'feed' ) );
$rss_link = '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $url . '" />';
}
// Output
echo $rss_link;
$url = esc_url( add_query_arg( 'story_id', get_the_ID(), home_url( 'feed/rss-chapters' ) ) );
$rss_link = '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $url . '" />';
}
// RSS Feed if chapter...
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post_id );
if ( $post_type == 'fcn_chapter' && ! empty( $story_id ) && ! $skip_to_default ) {
$title = sprintf(
_x( '%1$s - %2$s Chapters', 'Story Feed: [Site] - [Story] Chapters.', 'fictioneer' ),
FICTIONEER_SITE_NAME,
get_the_title( $story_id )
);
$url = esc_url( add_query_arg( 'story_id', $story_id, home_url( 'feed/rss-chapters' ) ) );
$rss_link = '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $url . '" />';
}
// Default RSS Feed
if ( empty( $rss_link ) ) {
$title = sprintf(
_x( '%s Feed', '[Site] Feed', 'fictioneer' ),
FICTIONEER_SITE_NAME
);
$url = esc_url( home_url( 'feed' ) );
$rss_link = '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $url . '" />';
}
// Output
echo $rss_link;
}
if ( get_option( 'fictioneer_enable_theme_rss' ) ) {
@ -573,37 +553,35 @@ add_filter( 'the_password_form', 'fictioneer_password_form', 10, 1 );
// ADD ID TO CONTENT PARAGRAPHS IN CHAPTERS
// =============================================================================
if ( ! function_exists( 'fictioneer_add_chapter_paragraph_id' ) ) {
/**
* Adds incrementing ID to chapter paragraphs
*
* @since 3.0
* @license CC BY-SA 3.0
* @link https://wordpress.stackexchange.com/a/152169/223620
*
* @param string $content The content.
* @return string $content The modified content.
*/
/**
* Adds incrementing ID to chapter paragraphs
*
* @since 3.0
* @license CC BY-SA 3.0
* @link https://wordpress.stackexchange.com/a/152169/223620
*
* @param string $content The content.
* @return string $content The modified content.
*/
function fictioneer_add_chapter_paragraph_id( $content ) {
global $post;
function fictioneer_add_chapter_paragraph_id( $content ) {
global $post;
if (
get_post_type() != 'fcn_chapter' ||
! in_the_loop() ||
! is_main_query() ||
post_password_required()
) return $content;
if (
get_post_type() != 'fcn_chapter' ||
! in_the_loop() ||
! is_main_query() ||
post_password_required()
) return $content;
return preg_replace_callback(
'|<p|',
function ( $matches ) {
static $i = 0;
return sprintf( '<p id="paragraph-%d" data-paragraph-id="%d" ', $i, $i++ );
},
$content
);
}
return preg_replace_callback(
'|<p|',
function ( $matches ) {
static $i = 0;
return sprintf( '<p id="paragraph-%d" data-paragraph-id="%d" ', $i, $i++ );
},
$content
);
}
add_filter( 'the_content', 'fictioneer_add_chapter_paragraph_id', 10, 1 );
@ -611,67 +589,65 @@ add_filter( 'the_content', 'fictioneer_add_chapter_paragraph_id', 10, 1 );
// ADD LIGHTBOX TO POST IMAGES
// =============================================================================
if ( ! function_exists( 'fictioneer_add_lightbox_to_post_images' ) ) {
/**
* Adds lightbox data attributes to post images
*
* @since 3.0
* @license CC BY-SA 3.0
* @link https://wordpress.stackexchange.com/a/84542/223620
* @link https://jhtechservices.com/changing-your-image-markup-in-wordpress/
*
* @param string $content The content.
* @return string $content The modified content.
*/
/**
* Adds lightbox data attributes to post images
*
* @since 3.0
* @license CC BY-SA 3.0
* @link https://wordpress.stackexchange.com/a/84542/223620
* @link https://jhtechservices.com/changing-your-image-markup-in-wordpress/
*
* @param string $content The content.
* @return string $content The modified content.
*/
function fictioneer_add_lightbox_to_post_images( $content ) {
if ( empty( $content ) ) return $content;
function fictioneer_add_lightbox_to_post_images( $content ) {
if ( empty( $content ) ) return $content;
// Setup
libxml_use_internal_errors( true );
$doc = new DOMDocument();
$doc->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
$images = $doc->getElementsByTagName( 'img' );
// Setup
libxml_use_internal_errors( true );
$doc = new DOMDocument();
$doc->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
$images = $doc->getElementsByTagName( 'img' );
// Iterate over each img tag
foreach ( $images as $img ) {
$classes = $img->getAttribute( 'class' );
$parent = $img->parentNode;
$parent_classes = $parent->getAttribute( 'class' );
$parent_href = strtolower( $parent->getAttribute( 'href' ) );
// Iterate over each img tag
foreach ( $images as $img ) {
$classes = $img->getAttribute( 'class' );
$parent = $img->parentNode;
$parent_classes = $parent->getAttribute( 'class' );
$parent_href = strtolower( $parent->getAttribute( 'href' ) );
// Abort if...
if (
str_contains( $classes . $parent_classes, 'no-auto-lightbox' ) ||
$parent->hasAttribute( 'target' )
) continue;
// Abort if...
if (
str_contains( $classes . $parent_classes, 'no-auto-lightbox' ) ||
$parent->hasAttribute( 'target' )
) continue;
if (
$parent->hasAttribute( 'href' ) &&
! preg_match( '/(?<=\.jpg|jpeg|png|gif|webp|svg|avif|apng|tiff|ico)(?:$|[#?])/', $parent_href )
) continue;
if (
$parent->hasAttribute( 'href' ) &&
! preg_match( '/(?<=\.jpg|jpeg|png|gif|webp|svg|avif|apng|tiff|ico)(?:$|[#?])/', $parent_href )
) continue;
$src = $img->getAttribute( 'src' );
$id = preg_match( '/wp-image-([0-9]+)/i', $classes, $class_id );
$src = $img->getAttribute( 'src' );
$id = preg_match( '/wp-image-([0-9]+)/i', $classes, $class_id );
if ( $class_id ) {
$id = absint( $class_id[1] );
$img->setAttribute( 'data-attachment-id', $id );
}
if ( $class_id ) {
$id = absint( $class_id[1] );
$img->setAttribute( 'data-attachment-id', $id );
}
if ( wp_get_attachment_image_url( $id, 'full' ) ) {
$src = wp_get_attachment_image_url( $id, 'full' );
}
if ( wp_get_attachment_image_url( $id, 'full' ) ) {
$src = wp_get_attachment_image_url( $id, 'full' );
}
$img->setAttribute( 'data-src', $src );
$img->setAttribute( 'data-lightbox', '' );
$img->setAttribute( 'tabindex', '0' );
};
$img->setAttribute( 'data-src', $src );
$img->setAttribute( 'data-lightbox', '' );
$img->setAttribute( 'tabindex', '0' );
};
$content = $doc->saveHTML();
$content = $doc->saveHTML();
return $content;
}
return $content;
}
if ( get_option( 'fictioneer_enable_lightbox' ) ) {
@ -743,90 +719,88 @@ if ( get_option( 'fictioneer_remove_wp_svg_filters' ) ) {
// ADD CONSENT WRAPPER TO EMBEDS
// =============================================================================
if ( ! function_exists( 'fictioneer_embed_consent_wrappers' ) ) {
/**
* Wraps embeds into a consent box that must be clicked to load the embed.
*
* @since Fictioneer 3.0
*
* @param string $content The content.
*
* @return string The modified content.
*/
/**
* Wraps embeds into a consent box that must be clicked to load the embed.
*
* @since Fictioneer 3.0
*
* @param string $content The content.
*
* @return string The modified content.
*/
function fictioneer_embed_consent_wrappers( $content ) {
if( empty( $content ) ) return $content;
function fictioneer_embed_consent_wrappers( $content ) {
if( empty( $content ) ) return $content;
libxml_use_internal_errors( true );
$dom = new DOMDocument();
$dom->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
$xpath = new DomXPath( $dom );
libxml_use_internal_errors( true );
$dom = new DOMDocument();
$dom->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
$xpath = new DomXPath( $dom );
$iframes = $dom->getElementsByTagName( 'iframe' );
$twitter_timelines = $xpath->query( "//a[@class='twitter-timeline']/following-sibling::*[1]" );
$twitter_tweets = $xpath->query( "//blockquote[@class='twitter-tweet']/following-sibling::*[1]" );
$iframes = $dom->getElementsByTagName( 'iframe' );
$twitter_timelines = $xpath->query( "//a[@class='twitter-timeline']/following-sibling::*[1]" );
$twitter_tweets = $xpath->query( "//blockquote[@class='twitter-tweet']/following-sibling::*[1]" );
// Process iframes
foreach ( $iframes as $iframe ) {
$src = $iframe->getAttribute( 'src' );
$title = htmlspecialchars( $iframe->getAttribute( 'title' ) );
$title = ( ! $title || $title == '') ? 'embedded content' : $title;
// Process iframes
foreach ( $iframes as $iframe ) {
$src = $iframe->getAttribute( 'src' );
$title = htmlspecialchars( $iframe->getAttribute( 'title' ) );
$title = ( ! $title || $title == '') ? 'embedded content' : $title;
$iframe->removeAttribute('src');
$iframe->removeAttribute('src');
$consent_element = $dom->createElement( 'button' );
$consent_element->setAttribute( 'type', 'button' );
$consent_element->setAttribute( 'class', 'iframe-consent' );
$consent_element->setAttribute( 'data-src', $src );
$consent_element->nodeValue = sprintf(
__( 'Click to load %s with third-party consent.', 'fictioneer' ),
$title
);
$consent_element = $dom->createElement( 'button' );
$consent_element->setAttribute( 'type', 'button' );
$consent_element->setAttribute( 'class', 'iframe-consent' );
$consent_element->setAttribute( 'data-src', $src );
$consent_element->nodeValue = sprintf(
__( 'Click to load %s with third-party consent.', 'fictioneer' ),
$title
);
$embed_logo = $dom->createElement( 'div' );
$embed_logo->setAttribute( 'class', 'embed-logo' );
$embed_logo = $dom->createElement( 'div' );
$embed_logo->setAttribute( 'class', 'embed-logo' );
$iframe->parentNode->insertBefore( $consent_element );
$iframe->parentNode->insertBefore( $embed_logo );
}
// Process Twitter timelines
foreach ( $twitter_timelines as $twitter ) {
$src = $twitter->getAttribute( 'src' );
$twitter->removeAttribute( 'src' );
$twitter->previousSibling->nodeValue = '';
$consent_element = $dom->createElement( 'div' );
$consent_element->setAttribute( 'class', 'twitter-consent' );
$consent_element->setAttribute( 'data-src', $src );
$consent_element->nodeValue = sprintf(
__( 'Click to load %s with third-party consent.', 'fictioneer' ),
__( 'Twitter', 'fictioneer' )
);
$twitter->parentNode->insertBefore( $consent_element );
}
// Process Twitter tweets
foreach ( $twitter_tweets as $twitter ) {
$src = $twitter->getAttribute( 'src' );
$twitter->removeAttribute( 'src' );
$consent_element = $dom->createElement( 'div' );
$consent_element->setAttribute( 'class', 'twitter-consent' );
$consent_element->setAttribute( 'data-src', $src );
$consent_element->nodeValue = sprintf(
__( 'Click to load %s with third-party consent.', 'fictioneer' ),
__( 'Twitter', 'fictioneer' )
);
$twitter->parentNode->insertBefore( $consent_element );
}
return $dom->saveHTML();
$iframe->parentNode->insertBefore( $consent_element );
$iframe->parentNode->insertBefore( $embed_logo );
}
// Process Twitter timelines
foreach ( $twitter_timelines as $twitter ) {
$src = $twitter->getAttribute( 'src' );
$twitter->removeAttribute( 'src' );
$twitter->previousSibling->nodeValue = '';
$consent_element = $dom->createElement( 'div' );
$consent_element->setAttribute( 'class', 'twitter-consent' );
$consent_element->setAttribute( 'data-src', $src );
$consent_element->nodeValue = sprintf(
__( 'Click to load %s with third-party consent.', 'fictioneer' ),
__( 'Twitter', 'fictioneer' )
);
$twitter->parentNode->insertBefore( $consent_element );
}
// Process Twitter tweets
foreach ( $twitter_tweets as $twitter ) {
$src = $twitter->getAttribute( 'src' );
$twitter->removeAttribute( 'src' );
$consent_element = $dom->createElement( 'div' );
$consent_element->setAttribute( 'class', 'twitter-consent' );
$consent_element->setAttribute( 'data-src', $src );
$consent_element->nodeValue = sprintf(
__( 'Click to load %s with third-party consent.', 'fictioneer' ),
__( 'Twitter', 'fictioneer' )
);
$twitter->parentNode->insertBefore( $consent_element );
}
return $dom->saveHTML();
}
if ( get_option( 'fictioneer_consent_wrappers' ) ) {

File diff suppressed because it is too large Load Diff

View File

@ -4,49 +4,47 @@
// FIX COMMENT POST REDIRECT
// =============================================================================
if ( ! function_exists( 'fictioneer_redirect_comment' ) ) {
/**
* Fixes redirect after posting a comment
*
* Due to the modified query, after posting a comment, the commenter may be
* redirected to the wrong comment page. This resolves the issue and also adds
* a query argument with a comment's visibility code to allow guests without
* email and cookies to preview their comment for a limited time as set in
* fictioneer_theme_comment().
*
* @since Fictioneer 4.7
*
* @param string $location Default redirect URI.
* @param object $commentdata Comment data.
*
* @return string Either $location or a new redirect URI.
*/
function fictioneer_redirect_comment( $location, $commentdata ) {
if ( ! isset( $commentdata ) || empty( $commentdata->comment_post_ID ) ) {
return $location;
}
$visibility_code = get_comment_meta(
$commentdata->comment_ID,
'fictioneer_visibility_code',
true
);
if ( wp_get_referer() ) {
if ( $visibility_code && ! $commentdata->comment_approved ) {
return add_query_arg(
'commentcode',
$visibility_code['code'],
wp_get_referer() . '#comment-' . $commentdata->comment_ID
);
} else {
return wp_get_referer() . '#comment-' . $commentdata->comment_ID;
}
}
/**
* Fixes redirect after posting a comment
*
* Due to the modified query, after posting a comment, the commenter may be
* redirected to the wrong comment page. This resolves the issue and also adds
* a query argument with a comment's visibility code to allow guests without
* email and cookies to preview their comment for a limited time as set in
* fictioneer_theme_comment().
*
* @since Fictioneer 4.7
*
* @param string $location Default redirect URI.
* @param object $commentdata Comment data.
*
* @return string Either $location or a new redirect URI.
*/
function fictioneer_redirect_comment( $location, $commentdata ) {
if ( ! isset( $commentdata ) || empty( $commentdata->comment_post_ID ) ) {
return $location;
}
$visibility_code = get_comment_meta(
$commentdata->comment_ID,
'fictioneer_visibility_code',
true
);
if ( wp_get_referer() ) {
if ( $visibility_code && ! $commentdata->comment_approved ) {
return add_query_arg(
'commentcode',
$visibility_code['code'],
wp_get_referer() . '#comment-' . $commentdata->comment_ID
);
} else {
return wp_get_referer() . '#comment-' . $commentdata->comment_ID;
}
}
return $location;
}
if ( ! get_option( 'fictioneer_disable_comment_query' ) ) {
@ -71,90 +69,88 @@ if ( get_option( 'fictioneer_do_not_save_comment_ip' ) ) {
// PREPROCESS COMMENTS
// =============================================================================
if ( ! function_exists( 'fictioneer_preprocess_comment' ) ) {
/**
* Applies anti-spam measures, checks for flags, filters the content, etc.
*
* @since Fictioneer 4.7
*
* @param array $commentdata Comment data.
*
* @return array $commentdata The preprocessed comment data.
*/
/**
* Applies anti-spam measures, checks for flags, filters the content, etc.
*
* @since Fictioneer 4.7
*
* @param array $commentdata Comment data.
*
* @return array $commentdata The preprocessed comment data.
*/
function fictioneer_preprocess_comment( $commentdata ) {
// Setup
$current_user = wp_get_current_user();
$user_id = $current_user ? $current_user->ID : false;
$is_ajax = get_option( 'fictioneer_enable_ajax_comment_submit' );
$is_admin = fictioneer_is_admin( $user_id );
function fictioneer_preprocess_comment( $commentdata ) {
// Setup
$current_user = wp_get_current_user();
$user_id = $current_user ? $current_user->ID : false;
$is_ajax = get_option( 'fictioneer_enable_ajax_comment_submit' );
$is_admin = fictioneer_is_admin( $user_id );
// Commenting disabled
if ( fictioneer_is_commenting_disabled( $commentdata['comment_post_ID'] ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Commenting disabled.', 'fictioneer' )] );
} else {
wp_die( __( 'Commenting disabled.', 'fictioneer' ) );
}
// Commenting disabled
if ( fictioneer_is_commenting_disabled( $commentdata['comment_post_ID'] ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Commenting disabled.', 'fictioneer' )] );
} else {
wp_die( __( 'Commenting disabled.', 'fictioneer' ) );
}
// Require JS to comment unless the commenter is logged-in as
// administrator, moderator, author, or editor.
if (
get_option( 'fictioneer_require_js_to_comment' ) &&
(
! $current_user ||
(
! $is_admin &&
! fictioneer_is_author( $user_id ) &&
! fictioneer_is_moderator( $user_id ) &&
! fictioneer_is_editor( $user_id )
)
)
) {
if ( ! isset( $_POST['fictioneer_comment_validator'] ) || ! $_POST['fictioneer_comment_validator'] ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Comment did not pass validation.', 'fictioneer' )] );
} else {
wp_die( __( 'Comment did not pass validation.', 'fictioneer' ) );
}
}
}
// Check fictioneer_admin_disable_commenting user flag
if ( $current_user->fictioneer_admin_disable_commenting ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Commenting capability disabled.', 'fictioneer' )] );
} else {
wp_die( __( 'Commenting capability disabled.', 'fictioneer' ) );
}
}
// Count links in comment the non-sophisticated way...
$link_count = substr_count( $commentdata['comment_content'], 'http' );
// No more than n links allowed (unless you are an administrator)
if (
get_option( 'fictioneer_enable_comment_link_limit' ) &&
$link_count > get_option( 'fictioneer_comment_link_limit_threshold', 3 ) &&
! fictioneer_is_admin( $current_user->ID )
) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Too many links.', 'fictioneer' )] );
} else {
wp_die( __( 'Too many links.', 'fictioneer' ) );
}
}
// Change allowed tags
global $allowedtags;
if ( ! $is_admin && get_option( 'fictioneer_disable_html_in_comments' ) ) {
$allowedtags = [];
}
return $commentdata;
}
// Require JS to comment unless the commenter is logged-in as
// administrator, moderator, author, or editor.
if (
get_option( 'fictioneer_require_js_to_comment' ) &&
(
! $current_user ||
(
! $is_admin &&
! fictioneer_is_author( $user_id ) &&
! fictioneer_is_moderator( $user_id ) &&
! fictioneer_is_editor( $user_id )
)
)
) {
if ( ! isset( $_POST['fictioneer_comment_validator'] ) || ! $_POST['fictioneer_comment_validator'] ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Comment did not pass validation.', 'fictioneer' )] );
} else {
wp_die( __( 'Comment did not pass validation.', 'fictioneer' ) );
}
}
}
// Check fictioneer_admin_disable_commenting user flag
if ( $current_user->fictioneer_admin_disable_commenting ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Commenting capability disabled.', 'fictioneer' )] );
} else {
wp_die( __( 'Commenting capability disabled.', 'fictioneer' ) );
}
}
// Count links in comment the non-sophisticated way...
$link_count = substr_count( $commentdata['comment_content'], 'http' );
// No more than n links allowed (unless you are an administrator)
if (
get_option( 'fictioneer_enable_comment_link_limit' ) &&
$link_count > get_option( 'fictioneer_comment_link_limit_threshold', 3 ) &&
! fictioneer_is_admin( $current_user->ID )
) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Too many links.', 'fictioneer' )] );
} else {
wp_die( __( 'Too many links.', 'fictioneer' ) );
}
}
// Change allowed tags
global $allowedtags;
if ( ! $is_admin && get_option( 'fictioneer_disable_html_in_comments' ) ) {
$allowedtags = [];
}
return $commentdata;
}
add_filter( 'preprocess_comment', 'fictioneer_preprocess_comment', 30, 1 );
@ -162,53 +158,66 @@ add_filter( 'preprocess_comment', 'fictioneer_preprocess_comment', 30, 1 );
// VALIDATE COMMENT FORM
// =============================================================================
if ( ! function_exists( 'fictioneer_validate_comment_form' ) ) {
/**
* Validate comment form submission
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/hooks/preprocess_comment/
*
* @param array $commentdata Comment data.
*/
/**
* Validate comment form submission
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/hooks/preprocess_comment/
*
* @param array $commentdata Comment data.
*/
function fictioneer_validate_comment_form( $commentdata ) {
// Setup
$parent_id = absint( $commentdata['comment_parent'] ?? 0 );
$is_ajax = get_option( 'fictioneer_enable_ajax_comment_submit' );
function fictioneer_validate_comment_form( $commentdata ) {
// Setup
$parent_id = absint( $commentdata['comment_parent'] ?? 0 );
$is_ajax = get_option( 'fictioneer_enable_ajax_comment_submit' );
// Check privacy consent for guests
if ( ! is_user_logged_in() && ! $is_ajax && get_option( 'wp_page_for_privacy_policy' ) ) {
// You cannot post a comment without accepting the privacy policy (Tested earlier on AJAX submit!)
if (
! isset( $_POST['fictioneer-privacy-policy-consent'] ) ||
! filter_var( $_POST['fictioneer-privacy-policy-consent'], FILTER_VALIDATE_BOOLEAN )
) {
wp_die( __( 'You did not accept the privacy policy.', 'fictioneer' ) );
}
// Check privacy consent for guests
if ( ! is_user_logged_in() && ! $is_ajax && get_option( 'wp_page_for_privacy_policy' ) ) {
// You cannot post a comment without accepting the privacy policy (Tested earlier on AJAX submit!)
if (
! isset( $_POST['fictioneer-privacy-policy-consent'] ) ||
! filter_var( $_POST['fictioneer-privacy-policy-consent'], FILTER_VALIDATE_BOOLEAN )
) {
wp_die( __( 'You did not accept the privacy policy.', 'fictioneer' ) );
}
}
// Abort if direct parent comment is deleted
if ( $parent_id && get_comment_meta( $parent_id, 'fictioneer_deleted_by_user', true ) ) {
// Abort if direct parent comment is deleted
if ( $parent_id && get_comment_meta( $parent_id, 'fictioneer_deleted_by_user', true ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'You cannot reply to deleted comments.', 'fictioneer' )] );
} else {
wp_die( __( 'You cannot reply to deleted comments.', 'fictioneer' ) );
}
}
// Abort if direct parent comment is marked as offensive
if ( $parent_id && get_comment_meta( $parent_id, 'fictioneer_marked_offensive', true ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'You cannot reply to comments marked as offensive.', 'fictioneer' )] );
} else {
wp_die( __( 'You cannot reply to comments marked as offensive.', 'fictioneer' ) );
}
}
// Abort if parent comment or ancestors are closed
if ( $parent_id && ! get_option( 'fictioneer_disable_comment_callback' ) ) {
if ( get_comment_meta( $parent_id, 'fictioneer_thread_closed', true ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'You cannot reply to deleted comments.', 'fictioneer' )] );
wp_send_json_error( ['error' => __( 'Comment thread is closed.', 'fictioneer' )] );
} else {
wp_die( __( 'You cannot reply to deleted comments.', 'fictioneer' ) );
wp_die( __( 'Comment thread is closed.', 'fictioneer' ) );
}
}
// Abort if direct parent comment is marked as offensive
if ( $parent_id && get_comment_meta( $parent_id, 'fictioneer_marked_offensive', true ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'You cannot reply to comments marked as offensive.', 'fictioneer' )] );
} else {
wp_die( __( 'You cannot reply to comments marked as offensive.', 'fictioneer' ) );
}
}
$ancestor = get_comment( $parent_id );
// Abort if parent comment or ancestors are closed
if ( $parent_id && ! get_option( 'fictioneer_disable_comment_callback' ) ) {
if ( get_comment_meta( $parent_id, 'fictioneer_thread_closed', true ) ) {
while ( $ancestor ) {
if ( ! is_object( $ancestor ) ) break;
// Ancestor closed?
if ( get_comment_meta( $ancestor->comment_ID, 'fictioneer_thread_closed', true ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Comment thread is closed.', 'fictioneer' )] );
} else {
@ -216,54 +225,39 @@ if ( ! function_exists( 'fictioneer_validate_comment_form' ) ) {
}
}
$ancestor = get_comment( $parent_id );
while ( $ancestor ) {
if ( ! is_object( $ancestor ) ) break;
// Ancestor closed?
if ( get_comment_meta( $ancestor->comment_ID, 'fictioneer_thread_closed', true ) ) {
if ( $is_ajax ) {
wp_send_json_error( ['error' => __( 'Comment thread is closed.', 'fictioneer' )] );
} else {
wp_die( __( 'Comment thread is closed.', 'fictioneer' ) );
}
}
// Next ancestor if any
$ancestor = $ancestor->comment_parent ? get_comment( $ancestor->comment_parent ) : false;
}
// Next ancestor if any
$ancestor = $ancestor->comment_parent ? get_comment( $ancestor->comment_parent ) : false;
}
// Mark comment as private
if (
get_option( 'fictioneer_enable_private_commenting' ) &&
(
isset( $_POST['fictioneer-private-comment-toggle'] ) &&
filter_var( $_POST['fictioneer-private-comment-toggle'], FILTER_VALIDATE_BOOLEAN )
)
) {
$commentdata['comment_type'] = 'private';
}
// Mark private if parent is private
if ( $parent_id && get_comment_type( $parent_id ) == 'private' ) {
$commentdata['comment_type'] = 'private';
}
// Enable email notification for replies
if (
get_option( 'fictioneer_enable_comment_notifications' ) &&
(
isset( $_POST['fictioneer-comment-notification-toggle'] ) &&
filter_var( $_POST['fictioneer-comment-notification-toggle'], FILTER_VALIDATE_BOOLEAN )
)
) {
$commentdata['notification'] = true;
}
return $commentdata;
}
// Mark comment as private
if (
get_option( 'fictioneer_enable_private_commenting' ) &&
(
isset( $_POST['fictioneer-private-comment-toggle'] ) &&
filter_var( $_POST['fictioneer-private-comment-toggle'], FILTER_VALIDATE_BOOLEAN )
)
) {
$commentdata['comment_type'] = 'private';
}
// Mark private if parent is private
if ( $parent_id && get_comment_type( $parent_id ) == 'private' ) {
$commentdata['comment_type'] = 'private';
}
// Enable email notification for replies
if (
get_option( 'fictioneer_enable_comment_notifications' ) &&
(
isset( $_POST['fictioneer-comment-notification-toggle'] ) &&
filter_var( $_POST['fictioneer-comment-notification-toggle'], FILTER_VALIDATE_BOOLEAN )
)
) {
$commentdata['notification'] = true;
}
return $commentdata;
}
if ( ! get_option( 'fictioneer_disable_comment_form' ) ) {
@ -274,83 +268,81 @@ if ( ! get_option( 'fictioneer_disable_comment_form' ) ) {
// COMMENT POST ACTION
// =============================================================================
if ( ! function_exists( 'fictioneer_comment_post' ) ) {
/**
* Fires after the comment has been inserted into the database
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/hooks/comment_post/
* @link https://github.com/WordPress/WordPress/blob/master/wp-includes/comment.php
* @see add_comment_meta()
* @see filter_var()
*
* @param int $comment_id The comment ID.
* @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
* @param array $commentdata Comment data.
*/
/**
* Fires after the comment has been inserted into the database
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/hooks/comment_post/
* @link https://github.com/WordPress/WordPress/blob/master/wp-includes/comment.php
* @see add_comment_meta()
* @see filter_var()
*
* @param int $comment_id The comment ID.
* @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
* @param array $commentdata Comment data.
*/
function fictioneer_comment_post( $comment_id, $comment_approved, $commentdata ) {
// Store privacy policy agreement in case theme comments are turned off
if (
isset( $_POST['fictioneer-privacy-policy-consent'] ) &&
filter_var( $_POST['fictioneer-privacy-policy-consent'], FILTER_VALIDATE_BOOLEAN )
) {
add_comment_meta( $comment_id, 'fictioneer_privacy_policy_accepted', true );
}
function fictioneer_comment_post( $comment_id, $comment_approved, $commentdata ) {
// Store privacy policy agreement in case theme comments are turned off
if (
isset( $_POST['fictioneer-privacy-policy-consent'] ) &&
filter_var( $_POST['fictioneer-privacy-policy-consent'], FILTER_VALIDATE_BOOLEAN )
) {
add_comment_meta( $comment_id, 'fictioneer_privacy_policy_accepted', true );
}
// Store visibility code for unapproved comments based on Unix seconds
add_comment_meta(
$comment_id,
'fictioneer_visibility_code',
array(
'timestamp' => time(),
'code' => uniqid() // Sufficiently unique for this purpose
),
true
);
// Store visibility code for unapproved comments based on Unix seconds
add_comment_meta(
$comment_id,
'fictioneer_visibility_code',
array(
'timestamp' => time(),
'code' => uniqid() // Sufficiently unique for this purpose
),
true
);
// Hold for moderation if user is flagged
if ( get_user_meta( $commentdata['user_id'], 'fictioneer_admin_always_moderate_comments', true ) ) {
wp_set_comment_status( $comment_id, 'hold' );
}
// Hold for moderation if user is flagged
if ( get_user_meta( $commentdata['user_id'], 'fictioneer_admin_always_moderate_comments', true ) ) {
wp_set_comment_status( $comment_id, 'hold' );
}
// Purge cache of post/page the comment is for
if ( fictioneer_caching_active() && isset( $commentdata['comment_post_ID'] ) ) {
fictioneer_purge_post_cache( $commentdata['comment_post_ID'] );
}
// Purge cache of post/page the comment is for
if ( fictioneer_caching_active() && isset( $commentdata['comment_post_ID'] ) ) {
fictioneer_purge_post_cache( $commentdata['comment_post_ID'] );
}
// Notification validator determines whether a subscription is active; change the validator
// and all associated comment reply subscriptions are terminated
$notification_validator = get_user_meta( $commentdata['user_id'], 'fictioneer_comment_reply_validator', true );
// Notification validator determines whether a subscription is active; change the validator
// and all associated comment reply subscriptions are terminated
$notification_validator = get_user_meta( $commentdata['user_id'], 'fictioneer_comment_reply_validator', true );
if ( empty( $notification_validator ) ) {
$notification_validator = time();
update_user_meta( $commentdata['user_id'], 'fictioneer_comment_reply_validator', $notification_validator );
}
if ( empty( $notification_validator ) ) {
$notification_validator = time();
update_user_meta( $commentdata['user_id'], 'fictioneer_comment_reply_validator', $notification_validator );
}
// If user opted for email notifications
if (
isset( $_POST['fictioneer-comment-notification-toggle'] ) &&
filter_var( $_POST['fictioneer-comment-notification-toggle'], FILTER_VALIDATE_BOOLEAN )
) {
add_comment_meta( $comment_id, 'fictioneer_send_notifications', $notification_validator );
// Reset code to stop notifications (sufficiently unique for this purpose)
add_comment_meta( $comment_id, 'fictioneer_notifications_reset', md5( wp_generate_password() ) );
}
// If user opted for email notifications
if (
isset( $_POST['fictioneer-comment-notification-toggle'] ) &&
filter_var( $_POST['fictioneer-comment-notification-toggle'], FILTER_VALIDATE_BOOLEAN )
) {
add_comment_meta( $comment_id, 'fictioneer_send_notifications', $notification_validator );
// Reset code to stop notifications (sufficiently unique for this purpose)
add_comment_meta( $comment_id, 'fictioneer_notifications_reset', md5( wp_generate_password() ) );
}
// Anything related to comment parent (if any)...
$parent_comment = get_comment( $commentdata['comment_parent'] );
// Anything related to comment parent (if any)...
$parent_comment = get_comment( $commentdata['comment_parent'] );
if ( $parent_comment ) {
$parent_notification_check = get_comment_meta( $commentdata['comment_parent'], 'fictioneer_send_notifications', true );
$parent_notification_validator = get_user_meta( $parent_comment->user_id, 'fictioneer_comment_reply_validator', true );
if ( $parent_comment ) {
$parent_notification_check = get_comment_meta( $commentdata['comment_parent'], 'fictioneer_send_notifications', true );
$parent_notification_validator = get_user_meta( $parent_comment->user_id, 'fictioneer_comment_reply_validator', true );
// Send notification to parent comment author (if wanted)
if ( get_option( 'fictioneer_enable_comment_notifications' ) && ! empty( $parent_notification_check ) ) {
// Parent comment user guest or member?
if ( $parent_comment->user_id == 0 || $parent_notification_check == $parent_notification_validator ) {
fictioneer_comment_notification( $parent_comment, $comment_id, $commentdata );
}
// Send notification to parent comment author (if wanted)
if ( get_option( 'fictioneer_enable_comment_notifications' ) && ! empty( $parent_notification_check ) ) {
// Parent comment user guest or member?
if ( $parent_comment->user_id == 0 || $parent_notification_check == $parent_notification_validator ) {
fictioneer_comment_notification( $parent_comment, $comment_id, $commentdata );
}
}
}
@ -364,17 +356,17 @@ if ( ! get_option( 'fictioneer_disable_comment_form' ) ) {
// COMMENT NOTIFICATION EMAIL
// =============================================================================
/**
* Send notification email about replies to commenter
*
* @since Fictioneer 5.0
*
* @param WP_Comment $parent Comment that was replied to.
* @param int $comment_id ID of the reply comment.
* @param array $commentdata Fields of the reply comment.
*/
if ( ! function_exists( 'fictioneer_comment_notification' ) ) {
/**
* Send notification email about replies to commenter
*
* @since Fictioneer 5.0
*
* @param WP_Comment $parent Comment that was replied to.
* @param int $comment_id ID of the reply comment.
* @param array $commentdata Fields of the reply comment.
*/
function fictioneer_comment_notification( WP_Comment $parent, int $comment_id, array $commentdata ) {
// Abort if...
if ( empty( $parent->comment_author_email ) || ! $comment_id || empty( $commentdata['comment_content'] ) ) {

View File

@ -41,72 +41,70 @@ if ( ! function_exists( 'fictioneer_get_comment_toolbar' ) ) {
// COMMENT FORM FIELDS
// =============================================================================
if ( ! function_exists( 'fictioneer_change_comment_fields' ) ) {
/**
* Change default fields of comment form
*
* @since Fictioneer 4.7
*
* @param array $fields Array of the default comment fields.
*
* @return array $fields Modified array of the default comment fields.
*/
function fictioneer_change_comment_fields( $fields ) {
// Remove URL (website) field
unset( $fields['url'] );
// Setup
$commenter = wp_get_current_commenter();
$cookie_checked_attribute = empty( $commenter['comment_author_email'] ) ? '' : ' checked';
$required = get_option( 'require_name_email' );
$required_attribute = $required ? ' required' : '';
$name_placeholder = $required ? __( 'Name *', 'fictioneer' ) : __( 'Name', 'fictioneer' );
$email_placeholder = $required ? __( 'Email (Gravatar) *', 'fictioneer' ) : __( 'Email (optional, Gravatar)', 'fictioneer' );
$privacy_policy_link = get_option( 'wp_page_for_privacy_policy' ) ? esc_url( get_privacy_policy_url() ) : false;
$hidden = FICTIONEER_COLLAPSE_COMMENT_FORM ? 'hidden' : '';
// Rebuild author field
$fields['author'] = '<div class="comment-form-author"><input type="text" id="author" name="author" data-lpignore="true" value="' . esc_attr( $commenter['comment_author'] ) . '"' . $required_attribute . ' maxlength="245" placeholder="' . $name_placeholder . '"></div>';
// Rebuild email field
$fields['email'] = '<div class="comment-form-email"><input type="text" id="email" name="email" data-lpignore="true" value="' . esc_attr( $commenter['comment_author_email'] ) . '" maxlength="100" aria-describedby="email-notes" placeholder="' . $email_placeholder . '"' . $required_attribute . '></div>';
// Open .fictioneer-respond__checkboxes wrapper
$fields['checkboxes'] = '<div class="fictioneer-respond__form-checkboxes">';
// Rebuild cookies field (ignores 'show_comments_cookies_opt_in' and is always enabled)
$fields['cookies'] = '<div class="comment-form-cookies-consent fictioneer-respond__checkbox-label-pair"><input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"' . $cookie_checked_attribute . '><label for="wp-comment-cookies-consent">' . fcntr( 'save_in_cookie' ) . '</label></div>';
// Build new privacy policy field
$privacy_policy = '';
if ( $privacy_policy_link ) {
$privacy_policy = '<div class="comment-form-privacy-policy-consent fictioneer-respond__checkbox-label-pair"><input id="fictioneer-privacy-policy-consent" name="fictioneer-privacy-policy-consent" type="checkbox" value="1" required' . $cookie_checked_attribute . '><label for="fictioneer-privacy-policy-consent">' . sprintf( fcntr( 'accept_privacy_policy' ), $privacy_policy_link ) . '</label></div>';
}
// Append checkboxes and close .fictioneer-respond__checkboxes wrapper
if ( get_option( 'show_comments_cookies_opt_in' ) ) {
$fields['checkboxes'] .= $fields['cookies'];
}
$fields['checkboxes'] .= $privacy_policy . '</div>';
// Disable now redundant cookies field (do not unset, this can cause issues with cache plugins apparently)
$fields['cookies'] = '';
/**
* Change default fields of comment form
*
* @since Fictioneer 4.7
*
* @param array $fields Array of the default comment fields.
*
* @return array $fields Modified array of the default comment fields.
* Open the .fictioneer-respond__bottom wrapper around all input fields below
* the textarea. It will be closed in the fictioneer_change_submit_field
* method. Also added is the .fictioneer-respond__form-identity wrapper
* around the author and email fields.
*/
function fictioneer_change_comment_fields( $fields ) {
// Remove URL (website) field
unset( $fields['url'] );
$fields['author'] = '<div class="fictioneer-respond__form-bottom ' . $hidden . '"><div class="fictioneer-respond__form-identity">' . $fields['author'];
$fields['email'] = $fields['email'] . '</div>';
// Setup
$commenter = wp_get_current_commenter();
$cookie_checked_attribute = empty( $commenter['comment_author_email'] ) ? '' : ' checked';
$required = get_option( 'require_name_email' );
$required_attribute = $required ? ' required' : '';
$name_placeholder = $required ? __( 'Name *', 'fictioneer' ) : __( 'Name', 'fictioneer' );
$email_placeholder = $required ? __( 'Email (Gravatar) *', 'fictioneer' ) : __( 'Email (optional, Gravatar)', 'fictioneer' );
$privacy_policy_link = get_option( 'wp_page_for_privacy_policy' ) ? esc_url( get_privacy_policy_url() ) : false;
$hidden = FICTIONEER_COLLAPSE_COMMENT_FORM ? 'hidden' : '';
// Rebuild author field
$fields['author'] = '<div class="comment-form-author"><input type="text" id="author" name="author" data-lpignore="true" value="' . esc_attr( $commenter['comment_author'] ) . '"' . $required_attribute . ' maxlength="245" placeholder="' . $name_placeholder . '"></div>';
// Rebuild email field
$fields['email'] = '<div class="comment-form-email"><input type="text" id="email" name="email" data-lpignore="true" value="' . esc_attr( $commenter['comment_author_email'] ) . '" maxlength="100" aria-describedby="email-notes" placeholder="' . $email_placeholder . '"' . $required_attribute . '></div>';
// Open .fictioneer-respond__checkboxes wrapper
$fields['checkboxes'] = '<div class="fictioneer-respond__form-checkboxes">';
// Rebuild cookies field (ignores 'show_comments_cookies_opt_in' and is always enabled)
$fields['cookies'] = '<div class="comment-form-cookies-consent fictioneer-respond__checkbox-label-pair"><input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"' . $cookie_checked_attribute . '><label for="wp-comment-cookies-consent">' . fcntr( 'save_in_cookie' ) . '</label></div>';
// Build new privacy policy field
$privacy_policy = '';
if ( $privacy_policy_link ) {
$privacy_policy = '<div class="comment-form-privacy-policy-consent fictioneer-respond__checkbox-label-pair"><input id="fictioneer-privacy-policy-consent" name="fictioneer-privacy-policy-consent" type="checkbox" value="1" required' . $cookie_checked_attribute . '><label for="fictioneer-privacy-policy-consent">' . sprintf( fcntr( 'accept_privacy_policy' ), $privacy_policy_link ) . '</label></div>';
}
// Append checkboxes and close .fictioneer-respond__checkboxes wrapper
if ( get_option( 'show_comments_cookies_opt_in' ) ) {
$fields['checkboxes'] .= $fields['cookies'];
}
$fields['checkboxes'] .= $privacy_policy . '</div>';
// Disable now redundant cookies field (do not unset, this can cause issues with cache plugins apparently)
$fields['cookies'] = '';
/**
* Open the .fictioneer-respond__bottom wrapper around all input fields below
* the textarea. It will be closed in the fictioneer_change_submit_field
* method. Also added is the .fictioneer-respond__form-identity wrapper
* around the author and email fields.
*/
$fields['author'] = '<div class="fictioneer-respond__form-bottom ' . $hidden . '"><div class="fictioneer-respond__form-identity">' . $fields['author'];
$fields['email'] = $fields['email'] . '</div>';
return $fields;
}
return $fields;
}
if ( ! get_option( 'fictioneer_disable_comment_form' ) ) {
@ -125,90 +123,88 @@ if ( ! get_option( 'fictioneer_disable_comment_bbcodes' ) && ! get_option( 'fict
// COMMENT FORM SUBMIT
// =============================================================================
if ( ! function_exists( 'fictioneer_change_submit_field' ) ) {
/**
* Change the submit field and add the Cancel Reply link
*
* @since Fictioneer 4.7
* @link https://github.com/WordPress/WordPress/blob/master/wp-includes/comment-template.php
* @link https://stackoverflow.com/a/57080105/17140970
*
* @param string $submit_field HTML markup for the submit field.
* @param array $args Arguments passed to comment_form().
*/
function fictioneer_change_submit_field( $submit_field, $args ) {
remove_filter( 'cancel_comment_reply_link', '__return_empty_string' );
// Setup
$close_bottom_container = is_user_logged_in() ? '' : '</div>';
$is_ajax = get_option( 'fictioneer_enable_ajax_comment_form' ) || get_option( 'fictioneer_enable_ajax_comments' );
$hidden = FICTIONEER_COLLAPSE_COMMENT_FORM ? 'hidden' : '';
/**
* Change the submit field and add the Cancel Reply link
*
* @since Fictioneer 4.7
* @link https://github.com/WordPress/WordPress/blob/master/wp-includes/comment-template.php
* @link https://stackoverflow.com/a/57080105/17140970
*
* @param string $submit_field HTML markup for the submit field.
* @param array $args Arguments passed to comment_form().
* Build the submit button with the comment_form arguments. Markup:
* <input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" />
*/
function fictioneer_change_submit_field( $submit_field, $args ) {
remove_filter( 'cancel_comment_reply_link', '__return_empty_string' );
$submit_button = sprintf(
'<input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" data-enabled="%4$s" data-disabled="Posting…">',
esc_attr( $args['name_submit'] ),
esc_attr( $args['id_submit'] ),
esc_attr( $args['class_submit'] ) . ' button fictioneer-respond__form-submit',
esc_attr( $args['label_submit'] )
);
// Setup
$close_bottom_container = is_user_logged_in() ? '' : '</div>';
$is_ajax = get_option( 'fictioneer_enable_ajax_comment_form' ) || get_option( 'fictioneer_enable_ajax_comments' );
$hidden = FICTIONEER_COLLAPSE_COMMENT_FORM ? 'hidden' : '';
// Private comment toggle
$private_toggle = '';
/**
* Build the submit button with the comment_form arguments. Markup:
* <input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" />
*/
$submit_button = sprintf(
'<input name="%1$s" type="submit" id="%2$s" class="%3$s" value="%4$s" data-enabled="%4$s" data-disabled="Posting…">',
esc_attr( $args['name_submit'] ),
esc_attr( $args['id_submit'] ),
esc_attr( $args['class_submit'] ) . ' button fictioneer-respond__form-submit',
esc_attr( $args['label_submit'] )
);
// Private comment toggle
$private_toggle = '';
if ( get_option( 'fictioneer_enable_private_commenting' ) ) {
$hint = esc_attr_x( 'Toggle to mark as private. Hides the comment from uninvolved viewers.', 'Comment form private toggle.', 'fictioneer' );
$private_toggle = '<div class="fictioneer-private-comment-toggle fictioneer-respond__form-toggle"><label class="comment-respond-option-toggle" tabindex="0" role="checkbox" aria-checked="false" aria-label="' . $hint . '"><input name="fictioneer-private-comment-toggle" id="fictioneer-private-comment-toggle" type="checkbox" tabindex="-1" onchange="fcn_ariaCheckedUpdate(this)" hidden><span class="tooltipped _mobile-tooltip" data-tooltip="' . $hint . '"><i class="fa-solid fa-eye off"></i><i class="fa-solid fa-eye-slash on"></i></span></label></div>';
}
// Email subscriptions toggle
$notification_toggle = '';
$notifications_blocked = get_the_author_meta( 'fictioneer_admin_disable_comment_notifications', get_current_user_id() );
$notification_checked = is_user_logged_in() && get_the_author_meta( 'fictioneer_comment_reply_notifications', get_current_user_id() ) && ! $notifications_blocked;
$notification_checked = $notification_checked && ( ! get_option( 'fictioneer_enable_public_cache_compatibility' ) || $is_ajax );
if ( get_option( 'fictioneer_enable_comment_notifications' ) && ! $notifications_blocked ) {
$hint = esc_attr_x( 'Toggle to get email notifications about direct replies.', 'Comment form email notification toggle.', 'fictioneer' );
$aria_checked = $notification_checked ? 'true' : 'false';
$notification_toggle = '<div class="fictioneer-comment-notification-toggle fictioneer-respond__form-toggle"><label class="comment-respond-option-toggle" tabindex="0" role="checkbox" aria-checked="' . $aria_checked . '" aria-label="' . $hint . '"><input name="fictioneer-comment-notification-toggle" id="fictioneer-comment-notification-toggle" type="checkbox" ' . checked( 1, $notification_checked, false ) . ' tabindex="-1" onchange="fcn_ariaCheckedUpdate(this)" hidden><span class="tooltipped _mobile-tooltip" data-tooltip="' . $hint . '"><i class="fa-solid fa-bell on"></i><i class="fa-solid fa-bell-slash off"></i></span></label></div>';
}
// Hidden parent_comment field
$parent_field = '<input type="hidden" name="comment_parent" id="comment_parent" value="0">';
// Hidden comment post ID field (fixed via JS)
$comment_post_id = '<input type="hidden" name="comment_post_ID" value="0" id="comment_post_ID">';
// Private comment notice for guests
$private_notice = '';
if ( ! is_user_logged_in() ) {
if ( get_option( 'fictioneer_enable_comment_notifications' ) ) {
$private_notice = __( '<div class="private-comment-notice hide-if-logged-in"><div><strong>Heads up!</strong> Your comment will be invisible to other guests and subscribers (except for replies), including you after a grace period. But if you submit an email address and toggle the bell icon, you will be sent replies until you cancel.</div></div>', 'fictioneer' );
} else {
$private_notice = __( '<div class="private-comment-notice hide-if-logged-in"><div><strong>Heads up!</strong> Your comment will be invisible to other guests and subscribers (except for replies), including you after a grace period.</div></div>', 'fictioneer' );
}
}
/**
* Enclose the submit fields in the .fictioneer-respond__form-actions wrapper,
* which will also include the Cancel Reply button if visible. Also close the
* .fictioneer-respond__bottom wrapper opened in fictioneer_change_comment_fields
* _before_ the submit fields and append the Cancel Reply link.
*/
return sprintf(
$close_bottom_container . '<div class="form-submit fictioneer-respond__form-actions ' . $hidden . '"><div>' . $private_toggle . $notification_toggle . '%1$s %2$s</div>%3$s</div><div class="fictioneer-respond__notices">' . $private_notice . '</div>',
$submit_button,
get_the_ID() ? get_comment_id_fields( get_the_ID() ) : ( $parent_field . $comment_post_id ),
preg_replace( '/<a/', '<a class="button _secondary"', get_cancel_comment_reply_link( 'Cancel' ) )
);
if ( get_option( 'fictioneer_enable_private_commenting' ) ) {
$hint = esc_attr_x( 'Toggle to mark as private. Hides the comment from uninvolved viewers.', 'Comment form private toggle.', 'fictioneer' );
$private_toggle = '<div class="fictioneer-private-comment-toggle fictioneer-respond__form-toggle"><label class="comment-respond-option-toggle" tabindex="0" role="checkbox" aria-checked="false" aria-label="' . $hint . '"><input name="fictioneer-private-comment-toggle" id="fictioneer-private-comment-toggle" type="checkbox" tabindex="-1" onchange="fcn_ariaCheckedUpdate(this)" hidden><span class="tooltipped _mobile-tooltip" data-tooltip="' . $hint . '"><i class="fa-solid fa-eye off"></i><i class="fa-solid fa-eye-slash on"></i></span></label></div>';
}
// Email subscriptions toggle
$notification_toggle = '';
$notifications_blocked = get_the_author_meta( 'fictioneer_admin_disable_comment_notifications', get_current_user_id() );
$notification_checked = is_user_logged_in() && get_the_author_meta( 'fictioneer_comment_reply_notifications', get_current_user_id() ) && ! $notifications_blocked;
$notification_checked = $notification_checked && ( ! get_option( 'fictioneer_enable_public_cache_compatibility' ) || $is_ajax );
if ( get_option( 'fictioneer_enable_comment_notifications' ) && ! $notifications_blocked ) {
$hint = esc_attr_x( 'Toggle to get email notifications about direct replies.', 'Comment form email notification toggle.', 'fictioneer' );
$aria_checked = $notification_checked ? 'true' : 'false';
$notification_toggle = '<div class="fictioneer-comment-notification-toggle fictioneer-respond__form-toggle"><label class="comment-respond-option-toggle" tabindex="0" role="checkbox" aria-checked="' . $aria_checked . '" aria-label="' . $hint . '"><input name="fictioneer-comment-notification-toggle" id="fictioneer-comment-notification-toggle" type="checkbox" ' . checked( 1, $notification_checked, false ) . ' tabindex="-1" onchange="fcn_ariaCheckedUpdate(this)" hidden><span class="tooltipped _mobile-tooltip" data-tooltip="' . $hint . '"><i class="fa-solid fa-bell on"></i><i class="fa-solid fa-bell-slash off"></i></span></label></div>';
}
// Hidden parent_comment field
$parent_field = '<input type="hidden" name="comment_parent" id="comment_parent" value="0">';
// Hidden comment post ID field (fixed via JS)
$comment_post_id = '<input type="hidden" name="comment_post_ID" value="0" id="comment_post_ID">';
// Private comment notice for guests
$private_notice = '';
if ( ! is_user_logged_in() ) {
if ( get_option( 'fictioneer_enable_comment_notifications' ) ) {
$private_notice = __( '<div class="private-comment-notice hide-if-logged-in"><div><strong>Heads up!</strong> Your comment will be invisible to other guests and subscribers (except for replies), including you after a grace period. But if you submit an email address and toggle the bell icon, you will be sent replies until you cancel.</div></div>', 'fictioneer' );
} else {
$private_notice = __( '<div class="private-comment-notice hide-if-logged-in"><div><strong>Heads up!</strong> Your comment will be invisible to other guests and subscribers (except for replies), including you after a grace period.</div></div>', 'fictioneer' );
}
}
/**
* Enclose the submit fields in the .fictioneer-respond__form-actions wrapper,
* which will also include the Cancel Reply button if visible. Also close the
* .fictioneer-respond__bottom wrapper opened in fictioneer_change_comment_fields
* _before_ the submit fields and append the Cancel Reply link.
*/
return sprintf(
$close_bottom_container . '<div class="form-submit fictioneer-respond__form-actions ' . $hidden . '"><div>' . $private_toggle . $notification_toggle . '%1$s %2$s</div>%3$s</div><div class="fictioneer-respond__notices">' . $private_notice . '</div>',
$submit_button,
get_the_ID() ? get_comment_id_fields( get_the_ID() ) : ( $parent_field . $comment_post_id ),
preg_replace( '/<a/', '<a class="button _secondary"', get_cancel_comment_reply_link( 'Cancel' ) )
);
}
if ( ! get_option( 'fictioneer_disable_comment_form' ) ) {

View File

@ -413,89 +413,87 @@ if ( ! function_exists( 'fictioneer_comment_mod_menu' ) ) {
// PERFORM COMMENT MODERATION ACTION - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_moderate_comment' ) ) {
/**
* Performs comment moderation action via AJAX
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
*/
/**
* Performs comment moderation action via AJAX
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
*/
function fictioneer_ajax_moderate_comment() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_moderate_comment() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
if ( ! current_user_can( 'moderate_comments' ) ) {
wp_send_json_error( ['error' => __( 'Permission denied!', 'fictioneer' )] );
}
if ( ! current_user_can( 'moderate_comments' ) ) {
wp_send_json_error( ['error' => __( 'Permission denied!', 'fictioneer' )] );
}
$comment_id = isset( $_POST['id'] ) ? fictioneer_validate_id( $_POST['id'] ) : false;
$comment_id = isset( $_POST['id'] ) ? fictioneer_validate_id( $_POST['id'] ) : false;
if ( empty( $_POST['operation'] ) || ! $comment_id ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
if ( empty( $_POST['operation'] ) || ! $comment_id ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
$operation = sanitize_text_field( $_POST['operation'] );
$operation = sanitize_text_field( $_POST['operation'] );
if ( ! in_array( $operation, ['spam', 'trash', 'approve', 'unapprove', 'close', 'open', 'sticky', 'unsticky'] ) ) {
wp_send_json_error( ['error' => __( 'Invalid operation.', 'fictioneer' )] );
}
if ( ! in_array( $operation, ['spam', 'trash', 'approve', 'unapprove', 'close', 'open', 'sticky', 'unsticky'] ) ) {
wp_send_json_error( ['error' => __( 'Invalid operation.', 'fictioneer' )] );
}
$comment = get_comment( $comment_id );
$comment = get_comment( $comment_id );
if ( ! $comment ) {
wp_send_json_error( ['error' => __( 'Comment not found in database.', 'fictioneer' )] );
}
if ( ! $comment ) {
wp_send_json_error( ['error' => __( 'Comment not found in database.', 'fictioneer' )] );
}
// Process and update
$result = false;
// Process and update
$result = false;
switch ( $operation ) {
case 'spam':
$result = wp_set_comment_status( $comment_id, 'spam' );
switch ( $operation ) {
case 'spam':
$result = wp_set_comment_status( $comment_id, 'spam' );
break;
case 'trash':
$result = wp_set_comment_status( $comment_id, 'trash' );
break;
case 'approve':
$result = wp_set_comment_status( $comment_id, 'approve' );
break;
case 'unapprove':
$result = wp_set_comment_status( $comment_id, 'hold' );
break;
case 'close':
$result = update_comment_meta( $comment_id, 'fictioneer_thread_closed', true );
break;
case 'open':
$result = update_comment_meta( $comment_id, 'fictioneer_thread_closed', false );
break;
case 'sticky':
if ( $comment->comment_parent ) {
wp_send_json_error( ['error' => __( 'Child comments cannot be sticky.', 'fictioneer' )] );
break;
case 'trash':
$result = wp_set_comment_status( $comment_id, 'trash' );
}
if ( get_comment_meta( $comment->comment_ID, 'fictioneer_deleted_by_user', true ) ) {
wp_send_json_error( ['error' => __( 'Deleted comments cannot be sticky.', 'fictioneer' )] );
break;
case 'approve':
$result = wp_set_comment_status( $comment_id, 'approve' );
break;
case 'unapprove':
$result = wp_set_comment_status( $comment_id, 'hold' );
break;
case 'close':
$result = update_comment_meta( $comment_id, 'fictioneer_thread_closed', true );
break;
case 'open':
$result = update_comment_meta( $comment_id, 'fictioneer_thread_closed', false );
break;
case 'sticky':
if ( $comment->comment_parent ) {
wp_send_json_error( ['error' => __( 'Child comments cannot be sticky.', 'fictioneer' )] );
break;
}
if ( get_comment_meta( $comment->comment_ID, 'fictioneer_deleted_by_user', true ) ) {
wp_send_json_error( ['error' => __( 'Deleted comments cannot be sticky.', 'fictioneer' )] );
break;
}
$result = update_comment_meta( $comment_id, 'fictioneer_sticky', true );
break;
case 'unsticky':
$result = update_comment_meta( $comment_id, 'fictioneer_sticky', false );
break;
}
}
$result = update_comment_meta( $comment_id, 'fictioneer_sticky', true );
break;
case 'unsticky':
$result = update_comment_meta( $comment_id, 'fictioneer_sticky', false );
break;
}
// Send result
if ( $result ) {
// Clear cache if necessary
if ( fictioneer_caching_active() ) fictioneer_purge_post_cache( $comment->comment_post_ID );
// Send result
if ( $result ) {
// Clear cache if necessary
if ( fictioneer_caching_active() ) fictioneer_purge_post_cache( $comment->comment_post_ID );
wp_send_json_success( ['id' => $comment_id, 'operation' => $operation] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Comment could not be updated.', 'fictioneer' )] );
}
wp_send_json_success( ['id' => $comment_id, 'operation' => $operation] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Comment could not be updated.', 'fictioneer' )] );
}
}
@ -507,132 +505,126 @@ if ( get_option( 'fictioneer_enable_ajax_comment_moderation' ) ) {
// REPORT COMMENTS
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_report_comment' ) ) {
/**
* Adds user to a comment's reports list via AJAX
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
*/
/**
* Adds user to a comment's reports list via AJAX
*
* @since Fictioneer 4.7
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
*/
function fictioneer_ajax_report_comment() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_report_comment() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
if ( empty( $_POST['id'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
if ( empty( $_POST['id'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
$comment_id = fictioneer_validate_id( $_POST['id'] );
$dubious = empty( $_POST['dubious'] ) ? false : $_POST['dubious'] == 'true';
$comment_id = fictioneer_validate_id( $_POST['id'] );
$dubious = empty( $_POST['dubious'] ) ? false : $_POST['dubious'] == 'true';
// Get comment
$comment = get_comment( $comment_id );
// Get comment
$comment = get_comment( $comment_id );
if ( ! $comment ) {
wp_send_json_error( ['error' => __( 'Comment not found.', 'fictioneer' )] );
}
if ( ! $comment ) {
wp_send_json_error( ['error' => __( 'Comment not found.', 'fictioneer' )] );
}
// Check if user is allowed to flag comments
if ( get_the_author_meta( 'fictioneer_admin_disable_reporting', $user->ID ) ) {
wp_send_json_error( ['error' => __( 'Reporting capability disabled.', 'fictioneer' )] );
}
// Check if user is allowed to flag comments
if ( get_the_author_meta( 'fictioneer_admin_disable_reporting', $user->ID ) ) {
wp_send_json_error( ['error' => __( 'Reporting capability disabled.', 'fictioneer' )] );
}
// Get current reports (array of user IDs)
$reports = get_comment_meta( $comment_id, 'fictioneer_user_reports', true );
$reports = $reports ? $reports : [];
// Get current reports (array of user IDs)
$reports = get_comment_meta( $comment_id, 'fictioneer_user_reports', true );
$reports = $reports ? $reports : [];
// Dubious if state not clear due to caching
if ( $dubious && array_key_exists( $user->ID, $reports ) ) {
wp_send_json_success(
array(
'id' => $comment_id,
'flagged' => true,
'resync' => __( 'You have already reported this comment. Click the flag again to retract the report.', 'fictioneer' )
)
);
}
// Check whether to add or remove the user from the array
if ( array_key_exists( $user->ID, $reports ) ) {
unset( $reports[ $user->ID ] );
} else {
$user_data = get_userdata( $user->ID );
$reports[ $user->ID ] = '<a href="' . get_edit_profile_url( $user->ID ) . '">' . $user_data->display_name . '</a>';
}
// Update comment meta
$result = update_comment_meta( $comment_id, 'fictioneer_user_reports', $reports );
if ( ! $result ) {
wp_send_json_error( ['error' => __( 'Database error. Report could not be saved.', 'fictioneer' )] );
}
// Send back to moderation?
$auto_moderation = get_comment_meta( $comment_id, 'fictioneer_auto_moderation', true );
if ( empty( $auto_moderation ) && count( $reports ) >= get_option( 'fictioneer_comment_report_threshold', 10 ) ) {
// Only ever auto-moderate once!
update_comment_meta( $comment_id, 'fictioneer_auto_moderation', time() );
// Set back to hold
wp_set_comment_status( $comment_id, 'hold' );
}
// Purge cache
if ( fictioneer_caching_active() ) fictioneer_purge_post_cache( $comment->comment_post_ID );
// Return result
// Dubious if state not clear due to caching
if ( $dubious && array_key_exists( $user->ID, $reports ) ) {
wp_send_json_success(
array(
'id' => $comment_id,
'flagged' => array_key_exists( $user->ID, $reports )
'flagged' => true,
'resync' => __( 'You have already reported this comment. Click the flag again to retract the report.', 'fictioneer' )
)
);
}
}
if ( ! function_exists( 'fictioneer_add_comments_report_column' ) ) {
/**
* Add comments reports column
*
* @since Fictioneer 4.7
* @link https://rudrastyh.com/wordpress/comments-table-columns.html
*
* @param array $cols Default columns.
*
* @return array Updated columns.
*/
function fictioneer_add_comments_report_column( $cols ) {
$new_cols = ['fictioneer_reports' => __( 'Reports', 'fictioneer' )];
$new_cols = array_slice( $cols, 0, 3, true ) + $new_cols + array_slice( $cols, 3, NULL, true );
return $new_cols;
// Check whether to add or remove the user from the array
if ( array_key_exists( $user->ID, $reports ) ) {
unset( $reports[ $user->ID ] );
} else {
$user_data = get_userdata( $user->ID );
$reports[ $user->ID ] = '<a href="' . get_edit_profile_url( $user->ID ) . '">' . $user_data->display_name . '</a>';
}
// Update comment meta
$result = update_comment_meta( $comment_id, 'fictioneer_user_reports', $reports );
if ( ! $result ) {
wp_send_json_error( ['error' => __( 'Database error. Report could not be saved.', 'fictioneer' )] );
}
// Send back to moderation?
$auto_moderation = get_comment_meta( $comment_id, 'fictioneer_auto_moderation', true );
if ( empty( $auto_moderation ) && count( $reports ) >= get_option( 'fictioneer_comment_report_threshold', 10 ) ) {
// Only ever auto-moderate once!
update_comment_meta( $comment_id, 'fictioneer_auto_moderation', time() );
// Set back to hold
wp_set_comment_status( $comment_id, 'hold' );
}
// Purge cache
if ( fictioneer_caching_active() ) fictioneer_purge_post_cache( $comment->comment_post_ID );
// Return result
wp_send_json_success(
array(
'id' => $comment_id,
'flagged' => array_key_exists( $user->ID, $reports )
)
);
}
if ( ! function_exists( 'fictioneer_add_comments_report_column_content' ) ) {
/**
* Echo content for comments reports column
*
* @since Fictioneer 4.7
* @link https://rudrastyh.com/wordpress/comments-table-columns.html
* @link https://developer.wordpress.org/reference/hooks/manage_comments_custom_column/
*
* @param string $column The custom column's name.
* @param string $comment_id The comment ID as a numeric string.
*/
/**
* Add comments reports column
*
* @since Fictioneer 4.7
* @link https://rudrastyh.com/wordpress/comments-table-columns.html
*
* @param array $cols Default columns.
*
* @return array Updated columns.
*/
function fictioneer_add_comments_report_column_content( $column, $comment_id ) {
$reports = get_comment_meta( $comment_id, 'fictioneer_user_reports', true );
function fictioneer_add_comments_report_column( $cols ) {
$new_cols = ['fictioneer_reports' => __( 'Reports', 'fictioneer' )];
$new_cols = array_slice( $cols, 0, 3, true ) + $new_cols + array_slice( $cols, 3, NULL, true );
return $new_cols;
}
if ( $reports && is_array( $reports ) ) {
echo count( $reports );
} else {
echo 0;
}
/**
* Echo content for comments reports column
*
* @since Fictioneer 4.7
* @link https://rudrastyh.com/wordpress/comments-table-columns.html
* @link https://developer.wordpress.org/reference/hooks/manage_comments_custom_column/
*
* @param string $column The custom column's name.
* @param string $comment_id The comment ID as a numeric string.
*/
function fictioneer_add_comments_report_column_content( $column, $comment_id ) {
$reports = get_comment_meta( $comment_id, 'fictioneer_user_reports', true );
if ( $reports && is_array( $reports ) ) {
echo count( $reports );
} else {
echo 0;
}
}

View File

@ -34,66 +34,64 @@ add_filter( 'comment_reply_link', 'fictioneer_comment_login_to_reply', 10, 4 );
// SHIFT STICKY COMMENTS
// =============================================================================
if ( ! function_exists( 'fictioneer_shift_sticky_comments' ) ) {
/**
* Query sticky comments and merge them in first
*
* @since Fictioneer 5.0
*
* @param array $comments Queried comments.
* @param int $post_id The post ID.
*
* @return array Comments with sticky ones on top.
*/
/**
* Query sticky comments and merge them in first
*
* @since Fictioneer 5.0
*
* @param array $comments Queried comments.
* @param int $post_id The post ID.
*
* @return array Comments with sticky ones on top.
*/
function fictioneer_shift_sticky_comments( $comments, $post_id ) {
// Query arguments
$stick_comments_args = array(
'status' => 'approve',
'post_id' => $post_id,
'parent' => 0,
'meta_query' => array(
'relation' => 'AND',
function fictioneer_shift_sticky_comments( $comments, $post_id ) {
// Query arguments
$stick_comments_args = array(
'status' => 'approve',
'post_id' => $post_id,
'parent' => 0,
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'fictioneer_sticky',
'value' => 1,
),
array(
'relation' => 'OR',
array(
'key' => 'fictioneer_sticky',
'value' => 1,
),
array(
'relation' => 'OR',
array(
'key' => 'fictioneer_marked_offensive',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'fictioneer_marked_offensive',
'value' => 1,
'compare' => '!=',
),
),
array(
'key' => 'fictioneer_deleted_by_user',
'key' => 'fictioneer_marked_offensive',
'compare' => 'NOT EXISTS',
)
),
array(
'key' => 'fictioneer_marked_offensive',
'value' => 1,
'compare' => '!=',
),
),
array(
'key' => 'fictioneer_deleted_by_user',
'compare' => 'NOT EXISTS',
)
);
)
);
if ( ! get_option( 'fictioneer_disable_comment_query' ) ) {
$stick_comments_args['type'] = ['comment', 'private'];
$stick_comments_args['order'] = get_option( 'comment_order' );
} else {
$stick_comments_args['type'] = ['comment'];
}
// Filter query arguments
$query_args = apply_filters( 'fictioneer_filter_comments_query', $stick_comments_args, $post_id );
// Query comments
$sticky_comments_query = new WP_Comment_Query( $query_args );
$sticky_comments = $sticky_comments_query->comments;
// Return merged comment lists
return array_merge( $sticky_comments, $comments );
if ( ! get_option( 'fictioneer_disable_comment_query' ) ) {
$stick_comments_args['type'] = ['comment', 'private'];
$stick_comments_args['order'] = get_option( 'comment_order' );
} else {
$stick_comments_args['type'] = ['comment'];
}
// Filter query arguments
$query_args = apply_filters( 'fictioneer_filter_comments_query', $stick_comments_args, $post_id );
// Query comments
$sticky_comments_query = new WP_Comment_Query( $query_args );
$sticky_comments = $sticky_comments_query->comments;
// Return merged comment lists
return array_merge( $sticky_comments, $comments );
}
if ( get_option( 'fictioneer_enable_sticky_comments' ) ) {
@ -370,30 +368,28 @@ if ( ! function_exists( 'fictioneer_get_comment_badge' ) ) {
// THEME COMMENT TEXT
// =============================================================================
if ( ! function_exists( 'fictioneer_replace_comment_line_breaks' ) ) {
/**
* Properly wrap empty lines into paragraphs
*
* @since Fictioneer 4.0
* @since Fictioneer 5.2.6 Updated and changed to not mess up some languages.
*
* @param string $comment_content The comment content.
*
* @return string $comment_content The modified comment content.
*/
/**
* Properly wrap empty lines into paragraphs
*
* @since Fictioneer 4.0
* @since Fictioneer 5.2.6 Updated and changed to not mess up some languages.
*
* @param string $comment_content The comment content.
*
* @return string $comment_content The modified comment content.
*/
function fictioneer_replace_comment_line_breaks( $comment_content ) {
$lines = preg_split( '/\R/', $comment_content );
function fictioneer_replace_comment_line_breaks( $comment_content ) {
$lines = preg_split( '/\R/', $comment_content );
$wrapped = array_map( function( $line ) {
if ( trim( $line ) === '' ) {
return '<p></p>';
}
return $line;
}, $lines );
$wrapped = array_map( function( $line ) {
if ( trim( $line ) === '' ) {
return '<p></p>';
}
return $line;
}, $lines );
return implode( PHP_EOL, $wrapped );
}
return implode( PHP_EOL, $wrapped );
}
if ( ! get_option( 'fictioneer_disable_comment_callback' ) ) {
@ -832,20 +828,18 @@ if ( ! function_exists( 'fictioneer_theme_comment' ) ) {
// THEME COMMENT PAGINATION MARKUP
// =============================================================================
if ( ! function_exists( 'fictioneer_pagination_markup' ) ) {
/**
* Change comment pagination markup
*
* @since Fictioneer 4.7
*
* @param string $template The default comment pagination template.
*
* @return string The modified comment pagination template.
*/
/**
* Change comment pagination markup
*
* @since Fictioneer 4.7
*
* @param string $template The default comment pagination template.
*
* @return string The modified comment pagination template.
*/
function fictioneer_pagination_markup( $template ) {
return '<nav class="pagination _padding-top %1$s" aria-label="%4$s" role="navigation">%3$s</nav>';
}
function fictioneer_pagination_markup( $template ) {
return '<nav class="pagination _padding-top %1$s" aria-label="%4$s" role="navigation">%3$s</nav>';
}
if ( ! get_option( 'fictioneer_disable_comment_pagination' ) ) {

View File

@ -83,149 +83,147 @@ if ( ! function_exists( 'fictioneer_build_story_comment' ) ) {
// SEND STORY COMMENTS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_request_story_comments' ) ) {
/**
* Sends a block of comments for a given story via AJAX
*
* @since Fictioneer 4.0
*/
/**
* Sends a block of comments for a given story via AJAX
*
* @since Fictioneer 4.0
*/
function fictioneer_request_story_comments() {
// Nonce
check_ajax_referer( 'fictioneer_nonce', 'nonce' );
function fictioneer_request_story_comments() {
// Nonce
check_ajax_referer( 'fictioneer_nonce', 'nonce' );
// Validations
$story_id = isset( $_GET['post_id'] ) ? fictioneer_validate_id( $_GET['post_id'], 'fcn_story' ) : false;
// Validations
$story_id = isset( $_GET['post_id'] ) ? fictioneer_validate_id( $_GET['post_id'], 'fcn_story' ) : false;
// Abort if not a story
if ( ! $story_id ) {
wp_send_json_error( ['error' => __( 'Comments could not be loaded.', 'fictioneer' )] );
}
// Abort if not a story
if ( ! $story_id ) {
wp_send_json_error( ['error' => __( 'Comments could not be loaded.', 'fictioneer' )] );
}
// Setup
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$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' );
$chapter_data = [];
$report_threshold = get_option( 'fictioneer_comment_report_threshold', 10 ) ?? 10;
// Setup
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$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' );
$chapter_data = [];
$report_threshold = get_option( 'fictioneer_comment_report_threshold', 10 ) ?? 10;
// Abort if no chapters have been found
if ( count( $chapter_ids ) < 1 ) die();
// Abort if no chapters have been found
if ( count( $chapter_ids ) < 1 ) die();
// Collect titles and permalinks of all chapters
foreach ( $chapter_ids as $chapter_id ) {
$chapter_data[ $chapter_id ] = [get_the_title( $chapter_id ), get_the_permalink( $chapter_id )];
}
// Collect titles and permalinks of all chapters
foreach ( $chapter_ids as $chapter_id ) {
$chapter_data[ $chapter_id ] = [get_the_title( $chapter_id ), get_the_permalink( $chapter_id )];
}
// Get comments
$comments = get_comments(
array(
'status' => 'approve',
'post_type' => ['fcn_chapter'],
'post__in' => $chapter_ids,
'number' => $comments_per_page,
'paged' => $page,
'meta_query' => array(
// Get comments
$comments = get_comments(
array(
'status' => 'approve',
'post_type' => ['fcn_chapter'],
'post__in' => $chapter_ids,
'number' => $comments_per_page,
'paged' => $page,
'meta_query' => array(
array(
'relation' => 'OR',
array(
'relation' => 'OR',
array(
'key' => 'fictioneer_marked_offensive',
'value' => [true, 1, '1'],
'compare' => 'NOT IN'
),
array(
'key' => 'fictioneer_marked_offensive',
'compare' => 'NOT EXISTS'
)
'key' => 'fictioneer_marked_offensive',
'value' => [true, 1, '1'],
'compare' => 'NOT IN'
),
array(
'key' => 'fictioneer_marked_offensive',
'compare' => 'NOT EXISTS'
)
)
)
);
)
);
// Calculate how many more comments (if any) are there after this batch
$remaining = $story['comment_count'] - $page * $comments_per_page;
// Calculate how many more comments (if any) are there after this batch
$remaining = $story['comment_count'] - $page * $comments_per_page;
// Start buffer
ob_start();
// Start buffer
ob_start();
// Make sure there are comments to display...
if ( count( $comments ) > 0 ) {
foreach ( $comments as $comment ) {
$reports = get_comment_meta( $comment->comment_ID, 'fictioneer_user_reports', true );
// Render empty if...
if ( get_comment_meta( $comment->comment_ID, 'fictioneer_deleted_by_user', true ) ) {
// Start HTML ---> ?>
<li class="fictioneer-comment _deleted">
<div class="fictioneer-comment__container">
<div class="fictioneer-comment__hidden-notice"><?php _e( 'Comment has been deleted by user.', 'fictioneer' ); ?></div>
</div>
</li>
<?php // <--- End HTML
continue;
}
// Hidden by reports...
if ( get_option( 'fictioneer_enable_comment_reporting' ) ) {
if ( ! empty( $reports ) && count( $reports ) >= $report_threshold ) {
// Start HTML ---> ?>
<li class="fictioneer-comment _deleted">
<div class="fictioneer-comment__container">
<div class="fictioneer-comment__hidden-notice"><?php _e( 'Comment is hidden due to negative reports.', 'fictioneer' ); ?></div>
</div>
</li>
<?php // <--- End HTML
}
}
// Make sure there are comments to display...
if ( count( $comments ) > 0 ) {
foreach ( $comments as $comment ) {
$reports = get_comment_meta( $comment->comment_ID, 'fictioneer_user_reports', true );
// Render empty if...
if ( get_comment_meta( $comment->comment_ID, 'fictioneer_deleted_by_user', true ) ) {
// Start HTML ---> ?>
<li class="fictioneer-comment _story-comment <?php echo $comment->comment_type; ?>">
<li class="fictioneer-comment _deleted">
<div class="fictioneer-comment__container">
<?php fictioneer_build_story_comment( $comment, $chapter_data ); ?>
<div class="fictioneer-comment__hidden-notice"><?php _e( 'Comment has been deleted by user.', 'fictioneer' ); ?></div>
</div>
</li>
<?php // <--- End HTML
continue;
}
// Load more button and loading placeholder if there are still comments left
if ( $remaining > 0 ) {
$load_n = $remaining > $comments_per_page ? $comments_per_page : $remaining;
// Start HTML ---> ?>
<li class="load-more-list-item">
<button class="load-more-comments-button"><?php
printf(
_n(
'Load next comment (may contain spoilers)',
'Load next %s comments (may contain spoilers)',
$load_n,
'fictioneer'
),
$load_n
);
?></button>
</li>
<div class="comments-loading-placeholder hidden"><i class="fas fa-spinner spinner"></i></div>
<?php // <--- End HTML
// Hidden by reports...
if ( get_option( 'fictioneer_enable_comment_reporting' ) ) {
if ( ! empty( $reports ) && count( $reports ) >= $report_threshold ) {
// Start HTML ---> ?>
<li class="fictioneer-comment _deleted">
<div class="fictioneer-comment__container">
<div class="fictioneer-comment__hidden-notice"><?php _e( 'Comment is hidden due to negative reports.', 'fictioneer' ); ?></div>
</div>
</li>
<?php // <--- End HTML
}
}
} else {
// Start HTML ---> ?>
<li class="fictioneer-comment private">
<li class="fictioneer-comment _story-comment <?php echo $comment->comment_type; ?>">
<div class="fictioneer-comment__container">
<div class="fictioneer-comment__hidden-notice"><?php _e( 'No public comments to display.', 'fictioneer' ); ?></div>
<?php fictioneer_build_story_comment( $comment, $chapter_data ); ?>
</div>
</li>
<?php // <--- End HTML
}
// Get buffer
$output = fictioneer_minify_html( ob_get_clean() );
// Load more button and loading placeholder if there are still comments left
if ( $remaining > 0 ) {
$load_n = $remaining > $comments_per_page ? $comments_per_page : $remaining;
// Return buffer
wp_send_json_success( ['html' => $output, 'postId' => $story_id, 'page' => $page] );
// Start HTML ---> ?>
<li class="load-more-list-item">
<button class="load-more-comments-button"><?php
printf(
_n(
'Load next comment (may contain spoilers)',
'Load next %s comments (may contain spoilers)',
$load_n,
'fictioneer'
),
$load_n
);
?></button>
</li>
<div class="comments-loading-placeholder hidden"><i class="fas fa-spinner spinner"></i></div>
<?php // <--- End HTML
}
} else {
// Start HTML ---> ?>
<li class="fictioneer-comment private">
<div class="fictioneer-comment__container">
<div class="fictioneer-comment__hidden-notice"><?php _e( 'No public comments to display.', 'fictioneer' ); ?></div>
</div>
</li>
<?php // <--- End HTML
}
// Get buffer
$output = fictioneer_minify_html( ob_get_clean() );
// Return buffer
wp_send_json_success( ['html' => $output, 'postId' => $story_id, 'page' => $page] );
}
add_action( 'wp_ajax_nopriv_fictioneer_request_story_comments', 'fictioneer_request_story_comments' );
add_action( 'wp_ajax_fictioneer_request_story_comments', 'fictioneer_request_story_comments' );

File diff suppressed because it is too large Load Diff

View File

@ -4,81 +4,79 @@
// LIST OF ALL COLLECTIONS
// =============================================================================
if ( ! function_exists( 'fictioneer_collections_list' ) ) {
/**
* Outputs the paginated card list for all collections
*
* @since 5.0
* @see collections.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['collections'] Paginated query of all published collections.
* @param string $args['queried_type'] The queried post type ('fcn_collection').
* @param array $args['query_args'] The query arguments used.
* @param string $args['order'] Current order. Default 'desc'.
* @param string $args['orderby'] Current orderby. Default 'modified'.
* @param int|string $args['ago'] Current date query argument part. Default 0.
*/
/**
* Outputs the paginated card list for all collections
*
* @since 5.0
* @see collections.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['collections'] Paginated query of all published collections.
* @param string $args['queried_type'] The queried post type ('fcn_collection').
* @param array $args['query_args'] The query arguments used.
* @param string $args['order'] Current order. Default 'desc'.
* @param string $args['orderby'] Current orderby. Default 'modified'.
* @param int|string $args['ago'] Current date query argument part. Default 0.
*/
function fictioneer_collections_list( $args ) {
// Start HTML ---> ?>
<section class="collections__list spacing-top">
<ul class="card-list" id="list-of-collections">
function fictioneer_collections_list( $args ) {
// Start HTML ---> ?>
<section class="collections__list spacing-top">
<ul class="card-list" id="list-of-collections">
<?php if ( $args['collections']->have_posts() ) : ?>
<?php
// Card arguments
$card_args = array(
'cache' => fictioneer_caching_active() && ! fictioneer_private_caching_active(),
'order' => $args['order'] ?? 'desc',
'orderby' => $args['orderby'] ?? 'modified',
'ago' => $args['ago'] ?? 0
);
// Filter card arguments
$card_args = apply_filters( 'fictioneer_filter_collections_card_args', $card_args, $args );
while ( $args['collections']->have_posts() ) {
$args['collections']->the_post();
get_template_part( 'partials/_card-collection', null, $card_args );
}
// Actions at end of results
do_action( 'fictioneer_collections_end_of_results', $args );
?>
<?php else: ?>
<?php do_action( 'fictioneer_collections_no_results', $args ); ?>
<li class="no-results">
<span><?php _e( 'No collections found.', 'fictioneer' ) ?></span>
</li>
<?php endif; wp_reset_postdata(); ?>
<?php if ( $args['collections']->have_posts() ) : ?>
<?php
$pag_args = array(
'base' => add_query_arg( 'paged', '%#%' ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $args['collections']->max_num_pages,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#list-of-collections'
// Card arguments
$card_args = array(
'cache' => fictioneer_caching_active() && ! fictioneer_private_caching_active(),
'order' => $args['order'] ?? 'desc',
'orderby' => $args['orderby'] ?? 'modified',
'ago' => $args['ago'] ?? 0
);
// Filter card arguments
$card_args = apply_filters( 'fictioneer_filter_collections_card_args', $card_args, $args );
while ( $args['collections']->have_posts() ) {
$args['collections']->the_post();
get_template_part( 'partials/_card-collection', null, $card_args );
}
// Actions at end of results
do_action( 'fictioneer_collections_end_of_results', $args );
?>
<?php if ( $args['collections']->max_num_pages > 1 ) : ?>
<li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li>
<?php endif; ?>
<?php else: ?>
</ul>
</section>
<?php // <--- End HTML
}
<?php do_action( 'fictioneer_collections_no_results', $args ); ?>
<li class="no-results">
<span><?php _e( 'No collections found.', 'fictioneer' ) ?></span>
</li>
<?php endif; wp_reset_postdata(); ?>
<?php
$pag_args = array(
'base' => add_query_arg( 'paged', '%#%' ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $args['collections']->max_num_pages,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#list-of-collections'
);
?>
<?php if ( $args['collections']->max_num_pages > 1 ) : ?>
<li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li>
<?php endif; ?>
</ul>
</section>
<?php // <--- End HTML
}
add_action( 'fictioneer_collections_after_content', 'fictioneer_collections_list', 30 );
@ -86,44 +84,42 @@ add_action( 'fictioneer_collections_after_content', 'fictioneer_collections_list
// COLLECTION TAGS & WARNINGS
// =============================================================================
if ( ! function_exists( 'fictioneer_collection_tags_and_warnings' ) ) {
/**
* Outputs the HTML for the collection page tags and warnings
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['collection'] Collection post object.
* @param int $args['collection_id'] The collection post ID.
* @param string $args['title'] Safe collection title.
* @param int $args['current_page'] Number of the current page or 1.
* @param int $args['max_pages'] Total number of pages or 1.
* @param array $args['featured_list'] IDs of featured items in the collection.
* @param WP_Query $args['featured_query'] Paginated query of featured items.
*/
/**
* Outputs the HTML for the collection page tags and warnings
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['collection'] Collection post object.
* @param int $args['collection_id'] The collection post ID.
* @param string $args['title'] Safe collection title.
* @param int $args['current_page'] Number of the current page or 1.
* @param int $args['max_pages'] Total number of pages or 1.
* @param array $args['featured_list'] IDs of featured items in the collection.
* @param WP_Query $args['featured_query'] Paginated query of featured items.
*/
function fictioneer_collection_tags_and_warnings( $args ) {
// Setup
$tags = get_the_tags( $args['collection_id'] );
$warnings = get_the_terms( $args['collection_id'], 'fcn_content_warning' );
function fictioneer_collection_tags_and_warnings( $args ) {
// Setup
$tags = get_the_tags( $args['collection_id'] );
$warnings = get_the_terms( $args['collection_id'], 'fcn_content_warning' );
// Flags
$tags_shown = $tags && ! get_option( 'fictioneer_hide_tags_on_pages' );
$warnings_shown = $warnings && ! get_option( 'fictioneer_hide_content_warnings_on_pages' );
// Flags
$tags_shown = $tags && ! get_option( 'fictioneer_hide_tags_on_pages' );
$warnings_shown = $warnings && ! get_option( 'fictioneer_hide_content_warnings_on_pages' );
// Abort conditions...
if ( ! $tags_shown && ! $warnings_shown ) return;
// Abort conditions...
if ( ! $tags_shown && ! $warnings_shown ) return;
// Prepare
$tag_args = [];
if ( $tags_shown ) $tag_args[] = $tags;
if ( $warnings_shown ) $tag_args[] = $warnings;
// Prepare
$tag_args = [];
if ( $tags_shown ) $tag_args[] = $tags;
if ( $warnings_shown ) $tag_args[] = $warnings;
// Start HTML ---> ?>
<section class="collection__tags-and-warnings tag-group"><?php
echo fictioneer_get_taxonomy_pills( $tag_args, '_secondary' );
?></section>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<section class="collection__tags-and-warnings tag-group"><?php
echo fictioneer_get_taxonomy_pills( $tag_args, '_secondary' );
?></section>
<?php // <--- End HTML
}
add_action( 'fictioneer_collection_after_content', 'fictioneer_collection_tags_and_warnings', 10 );
@ -131,28 +127,26 @@ add_action( 'fictioneer_collection_after_content', 'fictioneer_collection_tags_a
// COLLECTION STATISTICS
// =============================================================================
if ( ! function_exists( 'fictioneer_collection_statistics' ) ) {
/**
* Outputs the HTML for the collection page statistics
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['collection'] Collection post object.
* @param int $args['collection_id'] The collection post ID.
* @param string $args['title'] Safe collection title.
* @param int $args['current_page'] Number of the current page or 1.
* @param int $args['max_pages'] Total number of pages or 1.
* @param array $args['featured_list'] IDs of featured items in the collection.
* @param WP_Query $args['featured_query'] Paginated query of featured items.
*/
/**
* Outputs the HTML for the collection page statistics
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['collection'] Collection post object.
* @param int $args['collection_id'] The collection post ID.
* @param string $args['title'] Safe collection title.
* @param int $args['current_page'] Number of the current page or 1.
* @param int $args['max_pages'] Total number of pages or 1.
* @param array $args['featured_list'] IDs of featured items in the collection.
* @param WP_Query $args['featured_query'] Paginated query of featured items.
*/
function fictioneer_collection_statistics( $args ) {
// Abort if...
if ( post_password_required() ) return;
function fictioneer_collection_statistics( $args ) {
// Abort if...
if ( post_password_required() ) return;
// Render template
get_template_part( 'partials/_collection-statistics', null, $args );
}
// Render template
get_template_part( 'partials/_collection-statistics', null, $args );
}
add_action( 'fictioneer_collection_after_content', 'fictioneer_collection_statistics', 20 );
@ -160,68 +154,66 @@ add_action( 'fictioneer_collection_after_content', 'fictioneer_collection_statis
// COLLECTION FEATURED LIST
// =============================================================================
if ( ! function_exists( 'fictioneer_collection_featured_list' ) ) {
/**
* Outputs the HTML for the collection page featured list
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['collection'] Collection post object.
* @param int $args['collection_id'] The collection post ID.
* @param string $args['title'] Safe collection title.
* @param int $args['current_page'] Number of the current page or 1.
* @param int $args['max_pages'] Total number of pages or 1.
* @param array $args['featured_list'] IDs of featured items in the collection.
* @param WP_Query $args['featured_query'] Paginated query of featured items.
*/
/**
* Outputs the HTML for the collection page featured list
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['collection'] Collection post object.
* @param int $args['collection_id'] The collection post ID.
* @param string $args['title'] Safe collection title.
* @param int $args['current_page'] Number of the current page or 1.
* @param int $args['max_pages'] Total number of pages or 1.
* @param array $args['featured_list'] IDs of featured items in the collection.
* @param WP_Query $args['featured_query'] Paginated query of featured items.
*/
function fictioneer_collection_featured_list( $args ) {
// Abort if...
if ( post_password_required() ) return;
function fictioneer_collection_featured_list( $args ) {
// Abort if...
if ( post_password_required() ) return;
// Start HTML ---> ?>
<section class="collection__list spacing-top">
<ul id="featured-list" class="card-list">
<?php
// Render cards...
if ( $args['featured_query']->have_posts() ) {
// Loop through featured posts...
while ( $args['featured_query']->have_posts() ) {
// Setup
$args['featured_query']->the_post();
$card_args = array( 'show_type' => true );
// Start HTML ---> ?>
<section class="collection__list spacing-top">
<ul id="featured-list" class="card-list">
<?php
// Render cards...
if ( $args['featured_query']->have_posts() ) {
// Loop through featured posts...
while ( $args['featured_query']->have_posts() ) {
// Setup
$args['featured_query']->the_post();
$card_args = array( 'show_type' => true );
// Cached?
if ( fictioneer_caching_active() && ! fictioneer_private_caching_active() ) $card_args['cache'] = true;
// Cached?
if ( fictioneer_caching_active() && ! fictioneer_private_caching_active() ) $card_args['cache'] = true;
// Echo correct card
fictioneer_echo_card( $card_args );
}
// Restore global query
wp_reset_postdata();
// Setup pagination
$pag_args = array(
'base' => add_query_arg( 'pg', '%#%' ),
'format' => '?pg=%#%',
'current' => $args['current_page'],
'total' => $args['max_pages'] ?? 1,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#featured-list'
);
// Render pagination if necessary
if ( $args['max_pages'] > 1 ) {
?><li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li><?php
}
// Echo correct card
fictioneer_echo_card( $card_args );
}
?>
</ul>
</section>
<?php // <--- End HTML
}
// Restore global query
wp_reset_postdata();
// Setup pagination
$pag_args = array(
'base' => add_query_arg( 'pg', '%#%' ),
'format' => '?pg=%#%',
'current' => $args['current_page'],
'total' => $args['max_pages'] ?? 1,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#featured-list'
);
// Render pagination if necessary
if ( $args['max_pages'] > 1 ) {
?><li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li><?php
}
}
?>
</ul>
</section>
<?php // <--- End HTML
}
add_action( 'fictioneer_collection_after_content', 'fictioneer_collection_featured_list', 30 );

View File

@ -40,20 +40,18 @@ add_action( 'wp_head', 'fictioneer_add_fiction_css', 10 );
// BREADCRUMBS
// =============================================================================
if ( ! function_exists( 'fictioneer_breadcrumbs' ) ) {
/**
* Outputs the HTML for the breadcrumbs
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Post ID of the current page.
* @param string|null $args['post_type'] Optional. Post type of the current page.
* @param array $args['breadcrumbs'] Breadcrumb tuples with label (0) and link (1).
*/
/**
* Outputs the HTML for the breadcrumbs
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Post ID of the current page.
* @param string|null $args['post_type'] Optional. Post type of the current page.
* @param array $args['breadcrumbs'] Breadcrumb tuples with label (0) and link (1).
*/
function fictioneer_breadcrumbs( $args ) {
echo fictioneer_get_breadcrumbs( $args );
}
function fictioneer_breadcrumbs( $args ) {
echo fictioneer_get_breadcrumbs( $args );
}
add_action( 'fictioneer_site_footer', 'fictioneer_breadcrumbs', 10 );
@ -61,48 +59,46 @@ add_action( 'fictioneer_site_footer', 'fictioneer_breadcrumbs', 10 );
// FOOTER MENU ROW
// =============================================================================
if ( ! function_exists( 'fictioneer_footer_menu_row' ) ) {
/**
* Outputs the HTML for the footer menu and theme copyright notice
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Post ID of the current page.
* @param string|null $args['post_type'] Optional. Post type of the current page.
* @param array $args['breadcrumbs'] Breadcrumb tuples with label (0) and link (1).
*/
/**
* Outputs the HTML for the footer menu and theme copyright notice
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Post ID of the current page.
* @param string|null $args['post_type'] Optional. Post type of the current page.
* @param array $args['breadcrumbs'] Breadcrumb tuples with label (0) and link (1).
*/
function fictioneer_footer_menu_row( $args ) {
// Start HTML ---> ?>
<div class="footer__split-row">
<div class="footer__menu"><?php
$menu = get_transient( 'fictioneer_footer_menu' );
function fictioneer_footer_menu_row( $args ) {
// Start HTML ---> ?>
<div class="footer__split-row">
<div class="footer__menu"><?php
$menu = get_transient( 'fictioneer_footer_menu' );
if ( empty( $menu ) ) {
$menu = wp_nav_menu(
array(
'theme_location' => 'footer_menu',
'menu_class' => 'footer__menu-list',
'container' => '',
'echo' => false
)
);
if ( empty( $menu ) ) {
$menu = wp_nav_menu(
array(
'theme_location' => 'footer_menu',
'menu_class' => 'footer__menu-list',
'container' => '',
'echo' => false
)
);
$menu = str_replace( 'class="', 'class="footer__menu-list-item ', $menu );
$menu = str_replace( 'current_page_item', '', $menu );
$menu = str_replace( 'current-menu-item', '', $menu );
$menu = str_replace( 'aria-current="page"', '', $menu );
$menu = preg_replace( '/<\/li>\s*<li/', '</li><li', $menu );
$menu = str_replace( 'class="', 'class="footer__menu-list-item ', $menu );
$menu = str_replace( 'current_page_item', '', $menu );
$menu = str_replace( 'current-menu-item', '', $menu );
$menu = str_replace( 'aria-current="page"', '', $menu );
$menu = preg_replace( '/<\/li>\s*<li/', '</li><li', $menu );
set_transient( 'fictioneer_footer_menu', $menu );
}
set_transient( 'fictioneer_footer_menu', $menu );
}
echo $menu;
?></div>
<div class="footer__copyright"><?php echo fictioneer_get_footer_copyright_note( $args ); ?></div>
</div>
<?php // <--- End HTML
}
echo $menu;
?></div>
<div class="footer__copyright"><?php echo fictioneer_get_footer_copyright_note( $args ); ?></div>
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_site_footer', 'fictioneer_footer_menu_row', 20 );
@ -110,64 +106,62 @@ add_action( 'fictioneer_site_footer', 'fictioneer_footer_menu_row', 20 );
// OUTPUT MODALS
// =============================================================================
if ( ! function_exists( 'fictioneer_output_modals' ) ) {
/**
* Outputs the HTML for the modals
*
* @since Fictioneer 5.0.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param string|null $args['post_type'] Optional. Current post type.
* @param array $args['breadcrumbs'] Array of breadcrumb tuples with label (0) and link (1).
*/
/**
* Outputs the HTML for the modals
*
* @since Fictioneer 5.0.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param string|null $args['post_type'] Optional. Current post type.
* @param array $args['breadcrumbs'] Array of breadcrumb tuples with label (0) and link (1).
*/
function fictioneer_output_modals( $args ) {
// Formatting and suggestions
if ( ! empty( $args['post_id'] ) && $args['post_type'] == 'fcn_chapter' ) {
?><input id="modal-formatting-toggle" data-target="formatting-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-formatting' );
function fictioneer_output_modals( $args ) {
// Formatting and suggestions
if ( ! empty( $args['post_id'] ) && $args['post_type'] == 'fcn_chapter' ) {
?><input id="modal-formatting-toggle" data-target="formatting-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-formatting' );
?><input id="modal-tts-settings-toggle" data-target="tts-settings-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-tts-settings' );
?><input id="modal-tts-settings-toggle" data-target="tts-settings-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-tts-settings' );
if (
get_option( 'fictioneer_enable_suggestions' ) &&
! fictioneer_get_field( 'fictioneer_disable_commenting' ) &&
comments_open()
) {
?><input id="suggestions-modal-toggle" data-target="suggestions-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-suggestions' );
}
}
// OAuth2 login
if ( get_option( 'fictioneer_enable_oauth' ) && ! is_user_logged_in() ) {
?><input id="modal-login-toggle" data-target="login-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-login' );
}
// Social sharing
?><input id="modal-sharing-toggle" data-target="sharing-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-sharing' );
// Site settings
?><input id="modal-site-settings-toggle" data-target="site-settings-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-site-settings' );
// BBCodes tutorial
if (
! empty( $args['post_id'] ) &&
! post_password_required() &&
comments_open() &&
! fictioneer_is_commenting_disabled()
get_option( 'fictioneer_enable_suggestions' ) &&
! fictioneer_get_field( 'fictioneer_disable_commenting' ) &&
comments_open()
) {
?><input id="modal-bbcodes-toggle" data-target="bbcodes-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-bbcodes' );
?><input id="suggestions-modal-toggle" data-target="suggestions-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-suggestions' );
}
// Action to add modals
do_action( 'fictioneer_modals' );
}
// OAuth2 login
if ( get_option( 'fictioneer_enable_oauth' ) && ! is_user_logged_in() ) {
?><input id="modal-login-toggle" data-target="login-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-login' );
}
// Social sharing
?><input id="modal-sharing-toggle" data-target="sharing-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-sharing' );
// Site settings
?><input id="modal-site-settings-toggle" data-target="site-settings-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-site-settings' );
// BBCodes tutorial
if (
! empty( $args['post_id'] ) &&
! post_password_required() &&
comments_open() &&
! fictioneer_is_commenting_disabled()
) {
?><input id="modal-bbcodes-toggle" data-target="bbcodes-modal" type="checkbox" tabindex="-1" class="modal-toggle" autocomplete="off" hidden><?php
get_template_part( 'partials/_modal-bbcodes' );
}
// Action to add modals
do_action( 'fictioneer_modals' );
}
add_action( 'fictioneer_footer', 'fictioneer_output_modals' );
@ -175,21 +169,19 @@ add_action( 'fictioneer_footer', 'fictioneer_output_modals' );
// OUTPUT NAVIGATION BAR
// =============================================================================
if ( ! function_exists( 'fictioneer_navigation_bar' ) ) {
/**
* Outputs the HTML for the navigation bar
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
/**
* Outputs the HTML for the navigation bar
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
function fictioneer_navigation_bar( $args ) {
get_template_part( 'partials/_navigation', null, $args );
}
function fictioneer_navigation_bar( $args ) {
get_template_part( 'partials/_navigation', null, $args );
}
add_action( 'fictioneer_site', 'fictioneer_navigation_bar', 10 );
@ -197,53 +189,48 @@ add_action( 'fictioneer_site', 'fictioneer_navigation_bar', 10 );
// OUTPUT SITE HEADER
// =============================================================================
if ( ! function_exists( 'fictioneer_site_header' ) ) {
/**
* Outputs the HTML for the site header
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
/**
* Outputs the HTML for the site header
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
function fictioneer_site_header( $args ) {
get_template_part( 'partials/_site-header', null, $args );
}
function fictioneer_site_header( $args ) {
get_template_part( 'partials/_site-header', null, $args );
}
add_action( 'fictioneer_site', 'fictioneer_site_header', 20 );
// =============================================================================
// OUTPUT HEADER BACKGROUND
// =============================================================================
if ( ! function_exists( 'fictioneer_header_background' ) ) {
/**
* Outputs the HTML for the header background
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
/**
* Outputs the HTML for the header background
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
function fictioneer_header_background( $args ) {
// Abort if...
if ( ! isset( $args['header_image_url'] ) || ! $args['header_image_url'] ) return;
function fictioneer_header_background( $args ) {
// Abort if...
if ( ! isset( $args['header_image_url'] ) || ! $args['header_image_url'] ) return;
// Start HTML ---> ?>
<div class="header-background hide-on-fullscreen">
<div class="header-background__wrapper">
<img src="<?php echo $args['header_image_url']; ?>" alt="Header Background Image" class="header-background__image">
</div>
// Start HTML ---> ?>
<div class="header-background hide-on-fullscreen">
<div class="header-background__wrapper">
<img src="<?php echo $args['header_image_url']; ?>" alt="Header Background Image" class="header-background__image">
</div>
<?php // <--- End HTML
}
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_header', 'fictioneer_header_background', 10 );
@ -251,241 +238,239 @@ add_action( 'fictioneer_header', 'fictioneer_header_background', 10 );
// SORT, ORDER & FILTER QUERIES
// =============================================================================
if ( ! function_exists( 'fictioneer_sort_order_filter_interface' ) ) {
/**
* Renders interface to sort, order, and filter queries
*
* @since Fictioneer 5.4.0
*
* @param array $args {
* Array of arguments.
*
* @type int $current_page Optional. Current page if paginated or `1`.
* @type int $post_id Optional. Current post ID.
* @type string $queried_type Optional. Queried post type.
* @type array $query_args Optional. Query arguments used.
* @type string $order Current order or `desc`.
* @type string $orderby Current orderby or `'modified'`.
* @type int|string $ago Current date query argument part or `0`.
* }
*/
/**
* Renders interface to sort, order, and filter queries
*
* @since Fictioneer 5.4.0
*
* @param array $args {
* Array of arguments.
*
* @type int $current_page Optional. Current page if paginated or `1`.
* @type int $post_id Optional. Current post ID.
* @type string $queried_type Optional. Queried post type.
* @type array $query_args Optional. Query arguments used.
* @type string $order Current order or `desc`.
* @type string $orderby Current orderby or `'modified'`.
* @type int|string $ago Current date query argument part or `0`.
* }
*/
function fictioneer_sort_order_filter_interface( $args ) {
// Setup
$current_url = fictioneer_get_clean_url();
$post_type = null;
function fictioneer_sort_order_filter_interface( $args ) {
// Setup
$current_url = fictioneer_get_clean_url();
$post_type = null;
// Archive?
if ( is_archive() ) {
$post_type = strtolower( sanitize_text_field( $_GET['post_type'] ?? '' ) );
$post_type = array_intersect(
[ $post_type ],
['any', 'post', 'fcn_story', 'fcn_chapter', 'fcn_collection', 'fcn_recommendation']
);
$post_type = reset( $post_type ) ?: null;
}
// Post type?
if ( ! empty( $post_type ) ) {
$current_url = add_query_arg(
array( 'post_type' => $post_type ),
$current_url
);
}
// Order?
if ( ! empty( $args['order'] ) ) {
$current_url = add_query_arg(
array( 'order' => $args['order'] ),
$current_url
);
}
// Orderby?
if ( ! empty( $args['orderby'] ) ) {
$current_url = add_query_arg(
array( 'orderby' => $args['orderby'] ),
$current_url
);
}
// Ago?
if ( ! empty( $args['ago'] ) ) {
// Validate
if ( ! is_numeric( $args['ago'] ) && strtotime( $args['ago'] ) === false ) {
$args['ago'] = '0';
}
// Add if valid
if ( $args['ago'] != '0' ) {
$current_url = add_query_arg(
array( 'ago' => $args['ago'] ),
$current_url
);
}
}
// Post type menu options
$post_type_menu = array(
'any' => array(
'label' => __( 'All Posts', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'any' ), $current_url ) . '#sof'
),
'post' => array(
'label' => __( 'Blog Posts', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'post' ), $current_url ) . '#sof'
),
'fcn_story' => array(
'label' => __( 'Stories', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_story' ), $current_url ) . '#sof'
),
'fcn_chapter' => array(
'label' => __( 'Chapters', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_chapter' ), $current_url ) . '#sof'
),
'fcn_collection' => array(
'label' => __( 'Collections', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_collection' ), $current_url ) . '#sof'
),
'fcn_recommendation' => array(
'label' => __( 'Recommendations', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_recommendation' ), $current_url ) . '#sof'
)
// Archive?
if ( is_archive() ) {
$post_type = strtolower( sanitize_text_field( $_GET['post_type'] ?? '' ) );
$post_type = array_intersect(
[ $post_type ],
['any', 'post', 'fcn_story', 'fcn_chapter', 'fcn_collection', 'fcn_recommendation']
);
// Filter post type options
$post_type_menu = apply_filters( 'fictioneer_filter_sof_post_type_options', $post_type_menu, $current_url, $args );
// Order menu options
$orderby_menu = array(
'modified' => array(
'label' => __( 'Updated', 'fictioneer' ),
'url' => add_query_arg( array( 'orderby' => 'modified' ), $current_url ) . '#sof'
),
'date' => array(
'label' => __( 'Published', 'fictioneer' ),
'url' => add_query_arg( array( 'orderby' => 'date' ), $current_url ) . '#sof'
),
'title' => array(
'label' => __( 'By Title', 'fictioneer' ),
'url' => add_query_arg( array( 'orderby' => 'title' ), $current_url ) . '#sof'
)
);
// Filter orderby options
$orderby_menu = apply_filters( 'fictioneer_filter_sof_orderby_options', $orderby_menu, $current_url, $args );
// Date menu options
$date_menu = array(
'0' => array(
'label' => __( 'Any Date', 'fictioneer' ),
'url' => remove_query_arg( 'ago', $current_url ) . '#sof'
),
'1' => array(
'label' => __( 'Past 24 Hours', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => 1 ), $current_url ) . '#sof'
),
'3' => array(
'label' => __( 'Past 3 Days', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => 3 ), $current_url ) . '#sof'
),
'1_week_ago' => array(
'label' => __( 'Past Week', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '1 week ago' ) ), $current_url ) . '#sof'
),
'1_month_ago' => array(
'label' => __( 'Past Month', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '1 month ago' ) ), $current_url ) . '#sof'
),
'3_months_ago' => array(
'label' => __( 'Past 3 Months', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '3 months ago' ) ), $current_url ) . '#sof'
),
'6_months_ago' => array(
'label' => __( 'Past 6 Months', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '6 months ago' ) ), $current_url ) . '#sof'
),
'1_year_ago' => array(
'label' => __( 'Past Year', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '1 year ago' ) ), $current_url ) . '#sof'
)
);
// Filter date options
$date_menu = apply_filters( 'fictioneer_filter_sof_date_options', $date_menu, $current_url, $args );
// Order toggle link
$order_link = esc_url(
add_query_arg(
array( 'order' => $args['order'] === 'desc' ? 'asc' : 'desc' ),
$current_url
) . '#sof'
);
// Start HTML ---> ?>
<div id="sof" class="sort-order-filter">
<?php if ( is_archive() && ! empty( $post_type_menu ) ) : ?>
<div class="list-button _text popup-menu-toggle toggle-last-clicked" tabindex="0" role="button"><?php
echo $post_type_menu[ $post_type ?? 'any' ]['label'] ?? __( 'Unknown', 'fictioneer' );
echo '<div class="popup-menu _bottom _center">';
echo '<div class="popup-heading">' . __( 'Post Type', 'fictioneer' ) . '</div>';
foreach( $post_type_menu as $tuple ) {
$url = esc_url( $tuple['url'] );
echo "<a href='{$url}'>{$tuple['label']}</a>";
}
echo '</div>';
?></div>
<?php endif; ?>
<?php if ( ! empty( $orderby_menu ) ) : ?>
<div class="list-button _text popup-menu-toggle toggle-last-clicked" tabindex="0" role="button"><?php
echo $orderby_menu[ $args['orderby'] ]['label'] ?? __( 'Custom', 'fictioneer' );
echo '<div class="popup-menu _bottom _center">';
echo '<div class="popup-heading">' . __( 'Order By', 'fictioneer' ) . '</div>';
foreach( $orderby_menu as $tuple ) {
$url = esc_url( $tuple['url'] );
echo "<a href='{$url}'>{$tuple['label']}</a>";
}
echo '</div>';
?></div>
<?php endif; ?>
<?php if ( ! empty( $date_menu ) ) : ?>
<div class="list-button _text popup-menu-toggle toggle-last-clicked" tabindex="0" role="button"><?php
$key = str_replace( ' ', '_', $args['ago'] ?? '' );
if ( empty( $date_menu[ $key ]['label'] ) ) {
echo is_numeric( $args['ago'] ) ? sprintf(
__( 'Past %s Days', 'fictioneer' ), $args['ago']
) : urldecode( $args['ago'] );
} else {
echo $date_menu[ $key ]['label'];
}
echo '<div class="popup-menu _bottom _center">';
echo '<div class="popup-heading">' . __( 'Time Range', 'fictioneer' ) . '</div>';
foreach( $date_menu as $tuple ) {
$url = esc_url( $tuple['url'] );
echo "<a href='{$url}'>{$tuple['label']}</a>";
}
echo '</div>';
?></div>
<?php endif; ?>
<a class="list-button _order <?php echo $args['order'] === 'desc' ? '_on' : '_off'; ?>" href="<?php echo $order_link; ?>" aria-label="<?php esc_attr_e( 'Toggle between ascending and descending order', 'fictioneer' ); ?>">
<i class="fa-solid fa-arrow-up-short-wide _off"></i><i class="fa-solid fa-arrow-down-wide-short _on"></i>
</a>
</div>
<?php // <--- End HTML
$post_type = reset( $post_type ) ?: null;
}
// Post type?
if ( ! empty( $post_type ) ) {
$current_url = add_query_arg(
array( 'post_type' => $post_type ),
$current_url
);
}
// Order?
if ( ! empty( $args['order'] ) ) {
$current_url = add_query_arg(
array( 'order' => $args['order'] ),
$current_url
);
}
// Orderby?
if ( ! empty( $args['orderby'] ) ) {
$current_url = add_query_arg(
array( 'orderby' => $args['orderby'] ),
$current_url
);
}
// Ago?
if ( ! empty( $args['ago'] ) ) {
// Validate
if ( ! is_numeric( $args['ago'] ) && strtotime( $args['ago'] ) === false ) {
$args['ago'] = '0';
}
// Add if valid
if ( $args['ago'] != '0' ) {
$current_url = add_query_arg(
array( 'ago' => $args['ago'] ),
$current_url
);
}
}
// Post type menu options
$post_type_menu = array(
'any' => array(
'label' => __( 'All Posts', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'any' ), $current_url ) . '#sof'
),
'post' => array(
'label' => __( 'Blog Posts', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'post' ), $current_url ) . '#sof'
),
'fcn_story' => array(
'label' => __( 'Stories', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_story' ), $current_url ) . '#sof'
),
'fcn_chapter' => array(
'label' => __( 'Chapters', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_chapter' ), $current_url ) . '#sof'
),
'fcn_collection' => array(
'label' => __( 'Collections', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_collection' ), $current_url ) . '#sof'
),
'fcn_recommendation' => array(
'label' => __( 'Recommendations', 'fictioneer' ),
'url' => add_query_arg( array( 'post_type' => 'fcn_recommendation' ), $current_url ) . '#sof'
)
);
// Filter post type options
$post_type_menu = apply_filters( 'fictioneer_filter_sof_post_type_options', $post_type_menu, $current_url, $args );
// Order menu options
$orderby_menu = array(
'modified' => array(
'label' => __( 'Updated', 'fictioneer' ),
'url' => add_query_arg( array( 'orderby' => 'modified' ), $current_url ) . '#sof'
),
'date' => array(
'label' => __( 'Published', 'fictioneer' ),
'url' => add_query_arg( array( 'orderby' => 'date' ), $current_url ) . '#sof'
),
'title' => array(
'label' => __( 'By Title', 'fictioneer' ),
'url' => add_query_arg( array( 'orderby' => 'title' ), $current_url ) . '#sof'
)
);
// Filter orderby options
$orderby_menu = apply_filters( 'fictioneer_filter_sof_orderby_options', $orderby_menu, $current_url, $args );
// Date menu options
$date_menu = array(
'0' => array(
'label' => __( 'Any Date', 'fictioneer' ),
'url' => remove_query_arg( 'ago', $current_url ) . '#sof'
),
'1' => array(
'label' => __( 'Past 24 Hours', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => 1 ), $current_url ) . '#sof'
),
'3' => array(
'label' => __( 'Past 3 Days', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => 3 ), $current_url ) . '#sof'
),
'1_week_ago' => array(
'label' => __( 'Past Week', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '1 week ago' ) ), $current_url ) . '#sof'
),
'1_month_ago' => array(
'label' => __( 'Past Month', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '1 month ago' ) ), $current_url ) . '#sof'
),
'3_months_ago' => array(
'label' => __( 'Past 3 Months', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '3 months ago' ) ), $current_url ) . '#sof'
),
'6_months_ago' => array(
'label' => __( 'Past 6 Months', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '6 months ago' ) ), $current_url ) . '#sof'
),
'1_year_ago' => array(
'label' => __( 'Past Year', 'fictioneer' ),
'url' => add_query_arg( array( 'ago' => urlencode( '1 year ago' ) ), $current_url ) . '#sof'
)
);
// Filter date options
$date_menu = apply_filters( 'fictioneer_filter_sof_date_options', $date_menu, $current_url, $args );
// Order toggle link
$order_link = esc_url(
add_query_arg(
array( 'order' => $args['order'] === 'desc' ? 'asc' : 'desc' ),
$current_url
) . '#sof'
);
// Start HTML ---> ?>
<div id="sof" class="sort-order-filter">
<?php if ( is_archive() && ! empty( $post_type_menu ) ) : ?>
<div class="list-button _text popup-menu-toggle toggle-last-clicked" tabindex="0" role="button"><?php
echo $post_type_menu[ $post_type ?? 'any' ]['label'] ?? __( 'Unknown', 'fictioneer' );
echo '<div class="popup-menu _bottom _center">';
echo '<div class="popup-heading">' . __( 'Post Type', 'fictioneer' ) . '</div>';
foreach( $post_type_menu as $tuple ) {
$url = esc_url( $tuple['url'] );
echo "<a href='{$url}'>{$tuple['label']}</a>";
}
echo '</div>';
?></div>
<?php endif; ?>
<?php if ( ! empty( $orderby_menu ) ) : ?>
<div class="list-button _text popup-menu-toggle toggle-last-clicked" tabindex="0" role="button"><?php
echo $orderby_menu[ $args['orderby'] ]['label'] ?? __( 'Custom', 'fictioneer' );
echo '<div class="popup-menu _bottom _center">';
echo '<div class="popup-heading">' . __( 'Order By', 'fictioneer' ) . '</div>';
foreach( $orderby_menu as $tuple ) {
$url = esc_url( $tuple['url'] );
echo "<a href='{$url}'>{$tuple['label']}</a>";
}
echo '</div>';
?></div>
<?php endif; ?>
<?php if ( ! empty( $date_menu ) ) : ?>
<div class="list-button _text popup-menu-toggle toggle-last-clicked" tabindex="0" role="button"><?php
$key = str_replace( ' ', '_', $args['ago'] ?? '' );
if ( empty( $date_menu[ $key ]['label'] ) ) {
echo is_numeric( $args['ago'] ) ? sprintf(
__( 'Past %s Days', 'fictioneer' ), $args['ago']
) : urldecode( $args['ago'] );
} else {
echo $date_menu[ $key ]['label'];
}
echo '<div class="popup-menu _bottom _center">';
echo '<div class="popup-heading">' . __( 'Time Range', 'fictioneer' ) . '</div>';
foreach( $date_menu as $tuple ) {
$url = esc_url( $tuple['url'] );
echo "<a href='{$url}'>{$tuple['label']}</a>";
}
echo '</div>';
?></div>
<?php endif; ?>
<a class="list-button _order <?php echo $args['order'] === 'desc' ? '_on' : '_off'; ?>" href="<?php echo $order_link; ?>" aria-label="<?php esc_attr_e( 'Toggle between ascending and descending order', 'fictioneer' ); ?>">
<i class="fa-solid fa-arrow-up-short-wide _off"></i><i class="fa-solid fa-arrow-down-wide-short _on"></i>
</a>
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_stories_after_content', 'fictioneer_sort_order_filter_interface', 20 );
add_action( 'fictioneer_chapters_after_content', 'fictioneer_sort_order_filter_interface', 20 );

View File

@ -4,37 +4,35 @@
// OUTPUT MOBILE MENU
// =============================================================================
if ( ! function_exists( 'fictioneer_output_mobile_menu' ) ) {
/**
* Outputs the HTML for the mobile menu
*
* Outputs the HTML for the mobile menu. The mobile menu is structured into
* sections (top|center|bottom) > frames > panels. Only one frame per section
* should be displayed at a time, segmenting the menu.
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
/**
* Outputs the HTML for the mobile menu
*
* Outputs the HTML for the mobile menu. The mobile menu is structured into
* sections (top|center|bottom) > frames > panels. Only one frame per section
* should be displayed at a time, segmenting the menu.
*
* @since Fictioneer 5.0
*
* @param int|null $args['post_id'] Optional. Current post ID.
* @param int|null $args['story_id'] Optional. Current story ID (if chapter).
* @param string|boolean $args['header_image_url'] URL of the filtered header image or false.
* @param array $args['header_args'] Arguments passed to the header.php partial.
*/
function fictioneer_output_mobile_menu( $args ) {
// Start HTML ---> ?>
<input id="mobile-menu-toggle" type="checkbox" autocomplete="off" tabindex="-1" hidden>
<div class="mobile-menu">
<div class="mobile-menu__top"><?php do_action( 'fictioneer_mobile_menu_top' ); ?></div>
<div class="mobile-menu__center">
<div class="mobile-menu__frame _active" data-frame="main"><?php
do_action( 'fictioneer_mobile_menu_main_frame_panels' );
?></div>
<?php do_action( 'fictioneer_mobile_menu_center' ); ?>
</div>
<div class="mobile-menu__bottom"><?php do_action( 'fictioneer_mobile_menu_bottom' ); ?></div>
function fictioneer_output_mobile_menu( $args ) {
// Start HTML ---> ?>
<input id="mobile-menu-toggle" type="checkbox" autocomplete="off" tabindex="-1" hidden>
<div class="mobile-menu">
<div class="mobile-menu__top"><?php do_action( 'fictioneer_mobile_menu_top' ); ?></div>
<div class="mobile-menu__center">
<div class="mobile-menu__frame _active" data-frame="main"><?php
do_action( 'fictioneer_mobile_menu_main_frame_panels' );
?></div>
<?php do_action( 'fictioneer_mobile_menu_center' ); ?>
</div>
<?php // <--- End HTML
}
<div class="mobile-menu__bottom"><?php do_action( 'fictioneer_mobile_menu_bottom' ); ?></div>
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_body', 'fictioneer_output_mobile_menu', 20 );
@ -42,16 +40,14 @@ add_action( 'fictioneer_body', 'fictioneer_output_mobile_menu', 20 );
// MOBILE MENU USER HEADER MENU
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_user_icon_menu' ) ) {
/**
* Adds the _icon-menu.php partial to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds the _icon-menu.php partial to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_user_icon_menu() {
get_template_part( 'partials/_icon-menu', null, ['location' => 'in-mobile-menu'] );
}
function fictioneer_mobile_user_icon_menu() {
get_template_part( 'partials/_icon-menu', null, ['location' => 'in-mobile-menu'] );
}
add_action( 'fictioneer_mobile_menu_top', 'fictioneer_mobile_user_icon_menu', 10 );
@ -59,94 +55,92 @@ add_action( 'fictioneer_mobile_menu_top', 'fictioneer_mobile_user_icon_menu', 10
// MOBILE MENU QUICK BUTTONS
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_quick_buttons' ) ) {
/**
* Adds quick buttons to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds quick buttons to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_quick_buttons() {
// Setup
$post_type = is_archive() ? 'archive' : get_post_type();
$output = [];
function fictioneer_mobile_quick_buttons() {
// Setup
$post_type = is_archive() ? 'archive' : get_post_type();
$output = [];
// Build
// Build
ob_start();
// Start HTML ---> ?>
<label for="site-setting-minimal" class="button _quick"><span><?php _e( 'Minimalist', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['minimalist'] = ob_get_clean();
if ( $post_type === 'fcn_chapter' && ! is_search() ) {
ob_start();
// Start HTML ---> ?>
<button class="button _quick button-change-lightness" value="-0.2"><?php _e( 'Darken', 'fictioneer' ) ;?></button>
<?php // <--- End HTML
$output['darken'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="site-setting-minimal" class="button _quick"><span><?php _e( 'Minimalist', 'fictioneer' ); ?></span></label>
<button class="button _quick button-change-lightness" value="0.2"><?php _e( 'Brighten', 'fictioneer' ); ?></button>
<?php // <--- End HTML
$output['minimalist'] = ob_get_clean();
$output['brighten'] = ob_get_clean();
if ( $post_type === 'fcn_chapter' && ! is_search() ) {
ob_start();
// Start HTML ---> ?>
<button class="button _quick button-change-lightness" value="-0.2"><?php _e( 'Darken', 'fictioneer' ) ;?></button>
<?php // <--- End HTML
$output['darken'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="reader-settings-justify-toggle" class="button _quick"><span><?php _e( 'Justify', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['justify'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<button class="button _quick button-change-lightness" value="0.2"><?php _e( 'Brighten', 'fictioneer' ); ?></button>
<?php // <--- End HTML
$output['brighten'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="reader-settings-indent-toggle" class="button _quick"><span><?php _e( 'Indent', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['indent'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="reader-settings-justify-toggle" class="button _quick"><span><?php _e( 'Justify', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['justify'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="modal-formatting-toggle" class="button _quick"><span><?php echo fcntr( 'formatting' ); ?></span></label>
<?php // <--- End HTML
$output['formatting'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="reader-settings-indent-toggle" class="button _quick"><span><?php _e( 'Indent', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['indent'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<button class="button _quick button-change-font font-stepper" value="-1" id="quick-button-prev-font"><?php _e( 'Prev Font', 'fictioneer' ); ?></button>
<?php // <--- End HTML
$output['previous_font'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="modal-formatting-toggle" class="button _quick"><span><?php echo fcntr( 'formatting' ); ?></span></label>
<?php // <--- End HTML
$output['formatting'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<button class="button _quick button-change-font font-stepper" value="1" id="quick-button-next-font"><?php _e( 'Next Font', 'fictioneer' ); ?></button>
<?php // <--- End HTML
$output['next_font'] = ob_get_clean();
} else {
ob_start();
// Start HTML ---> ?>
<label for="site-setting-covers" class="button _quick"><span><?php _e( 'Covers', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['covers'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<button class="button _quick button-change-font font-stepper" value="-1" id="quick-button-prev-font"><?php _e( 'Prev Font', 'fictioneer' ); ?></button>
<?php // <--- End HTML
$output['previous_font'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="site-setting-background-textures" class="button _quick"><span><?php _e( 'Textures', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['textures'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<button class="button _quick button-change-font font-stepper" value="1" id="quick-button-next-font"><?php _e( 'Next Font', 'fictioneer' ); ?></button>
<?php // <--- End HTML
$output['next_font'] = ob_get_clean();
} else {
ob_start();
// Start HTML ---> ?>
<label for="site-setting-covers" class="button _quick"><span><?php _e( 'Covers', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['covers'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="site-setting-background-textures" class="button _quick"><span><?php _e( 'Textures', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['textures'] = ob_get_clean();
ob_start();
// Start HTML ---> ?>
<label for="site-setting-polygons" class="button _quick"><span><?php _e( 'Polygons', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['polygons'] = ob_get_clean();
}
// Apply filter
$output = apply_filters( 'fictioneer_filter_mobile_quick_buttons', $output );
// Return
echo implode( '', $output );
ob_start();
// Start HTML ---> ?>
<label for="site-setting-polygons" class="button _quick"><span><?php _e( 'Polygons', 'fictioneer' ); ?></span></label>
<?php // <--- End HTML
$output['polygons'] = ob_get_clean();
}
// Apply filter
$output = apply_filters( 'fictioneer_filter_mobile_quick_buttons', $output );
// Return
echo implode( '', $output );
}
add_action( 'fictioneer_mobile_menu_bottom', 'fictioneer_mobile_quick_buttons', 10 );
@ -154,34 +148,32 @@ add_action( 'fictioneer_mobile_menu_bottom', 'fictioneer_mobile_quick_buttons',
// MOBILE MENU FOLLOWS FRAME
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_follows_frame' ) ) {
/**
* Adds the Follows frame to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds the Follows frame to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_follows_frame() {
// Start HTML ---> ?>
<div class="mobile-menu__frame" data-frame="follows">
<div class="mobile-menu__panel mobile-menu__follows-panel">
<div class="mobile-menu__panel-header">
<button class="mobile-menu__back-button">
<i class="fa-solid fa-caret-left mobile-menu__item-icon"></i> <?php _e( 'Back', 'fictioneer' ); ?>
</button>
<button class="mark-follows-read mobile-menu__panel-action-button">
<i class="fa-solid fa-check"></i>
</button>
</div>
<div id="mobile-menu-follows-list" class="mobile-menu__list mobile-follow-notifications">
<div class="mobile-content-is-loading">
<i class="fa-solid fa-spinner fa-spin" style="--fa-animation-duration: .8s;"></i>
</div>
function fictioneer_mobile_follows_frame() {
// Start HTML ---> ?>
<div class="mobile-menu__frame" data-frame="follows">
<div class="mobile-menu__panel mobile-menu__follows-panel">
<div class="mobile-menu__panel-header">
<button class="mobile-menu__back-button">
<i class="fa-solid fa-caret-left mobile-menu__item-icon"></i> <?php _e( 'Back', 'fictioneer' ); ?>
</button>
<button class="mark-follows-read mobile-menu__panel-action-button">
<i class="fa-solid fa-check"></i>
</button>
</div>
<div id="mobile-menu-follows-list" class="mobile-menu__list mobile-follow-notifications">
<div class="mobile-content-is-loading">
<i class="fa-solid fa-spinner fa-spin" style="--fa-animation-duration: .8s;"></i>
</div>
</div>
</div>
<?php // <--- End HTML
}
</div>
<?php // <--- End HTML
}
if ( get_option( 'fictioneer_enable_follows' ) ) {
@ -192,32 +184,30 @@ if ( get_option( 'fictioneer_enable_follows' ) ) {
// MOBILE MENU BOOKMARKS FRAME
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_bookmarks_frame' ) ) {
/**
* Adds the bookmarks frame to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds the bookmarks frame to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_bookmarks_frame() {
get_template_part( 'partials/_template_mobile_bookmark' );
function fictioneer_mobile_bookmarks_frame() {
get_template_part( 'partials/_template_mobile_bookmark' );
// Start HTML ---> ?>
<div class="mobile-menu__frame" data-frame="bookmarks">
<div class="mobile-menu__panel mobile-menu__bookmarks-panel" data-editing="false">
<div class="mobile-menu__panel-header">
<button class="mobile-menu__back-button">
<i class="fa-solid fa-caret-left mobile-menu__item-icon"></i> <?php _e( 'Back', 'fictioneer' ); ?>
</button>
<button id="button-mobile-menu-toggle-bookmarks-edit" class="mobile-menu__panel-action-button">
<i class="fa-solid fa-pen off"></i><i class="fa-solid fa-check on"></i>
</button>
</div>
<ul class="mobile-menu__list mobile-menu__bookmark-list" data-empty="<?php echo fcntr( 'no_bookmarks', true ); ?>"></ul>
// Start HTML ---> ?>
<div class="mobile-menu__frame" data-frame="bookmarks">
<div class="mobile-menu__panel mobile-menu__bookmarks-panel" data-editing="false">
<div class="mobile-menu__panel-header">
<button class="mobile-menu__back-button">
<i class="fa-solid fa-caret-left mobile-menu__item-icon"></i> <?php _e( 'Back', 'fictioneer' ); ?>
</button>
<button id="button-mobile-menu-toggle-bookmarks-edit" class="mobile-menu__panel-action-button">
<i class="fa-solid fa-pen off"></i><i class="fa-solid fa-check on"></i>
</button>
</div>
<ul class="mobile-menu__list mobile-menu__bookmark-list" data-empty="<?php echo fcntr( 'no_bookmarks', true ); ?>"></ul>
</div>
<?php // <--- End HTML
}
</div>
<?php // <--- End HTML
}
if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
@ -228,30 +218,28 @@ if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
// MOBILE MENU CHAPTERS FRAME
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_chapters_frame' ) ) {
/**
* Adds the chapters frame to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds the chapters frame to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_chapters_frame() {
// Abort conditions
if ( get_post_type() != 'fcn_chapter' || is_archive() || is_search() ) return;
function fictioneer_mobile_chapters_frame() {
// Abort conditions
if ( get_post_type() != 'fcn_chapter' || is_archive() || is_search() ) return;
// Start HTML ---> ?>
<div class="mobile-menu__frame" data-frame="chapters">
<div class="mobile-menu__panel mobile-menu__chapters-panel">
<div class="mobile-menu__panel-header">
<button class="mobile-menu__back-button">
<i class="fa-solid fa-caret-left mobile-menu__item-icon"></i> <?php _e( 'Back', 'fictioneer' ); ?>
</button>
</div>
<div id="mobile-menu-chapters-list" class="mobile-menu__list _chapters"></div>
// Start HTML ---> ?>
<div class="mobile-menu__frame" data-frame="chapters">
<div class="mobile-menu__panel mobile-menu__chapters-panel">
<div class="mobile-menu__panel-header">
<button class="mobile-menu__back-button">
<i class="fa-solid fa-caret-left mobile-menu__item-icon"></i> <?php _e( 'Back', 'fictioneer' ); ?>
</button>
</div>
<div id="mobile-menu-chapters-list" class="mobile-menu__list _chapters"></div>
</div>
<?php // <--- End HTML
}
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_mobile_menu_center', 'fictioneer_mobile_chapters_frame', 30 );
@ -259,20 +247,18 @@ add_action( 'fictioneer_mobile_menu_center', 'fictioneer_mobile_chapters_frame',
// MOBILE MENU NAVIGATION PANEL
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_navigation_panel' ) ) {
/**
* Adds the navigation panel to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds the navigation panel to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_navigation_panel() {
// Start HTML ---> ?>
<nav id="mobile-navigation" class="mobile-navigation mobile-menu__panel"><?php
// Cloned from the main navigation via JS
?></nav>
<?php // <--- End HTML
}
function fictioneer_mobile_navigation_panel() {
// Start HTML ---> ?>
<nav id="mobile-navigation" class="mobile-navigation mobile-menu__panel"><?php
// Cloned from the main navigation via JS
?></nav>
<?php // <--- End HTML
}
add_action( 'fictioneer_mobile_menu_main_frame_panels', 'fictioneer_mobile_navigation_panel', 10 );
@ -280,55 +266,53 @@ add_action( 'fictioneer_mobile_menu_main_frame_panels', 'fictioneer_mobile_navig
// MOBILE MENU LISTS PANEL
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_lists_panel' ) ) {
/**
* Adds the lists panel to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds the lists panel to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_lists_panel() {
// Setup
$post_type = is_archive() ? 'archive' : get_post_type();
$output = [];
function fictioneer_mobile_lists_panel() {
// Setup
$post_type = is_archive() ? 'archive' : get_post_type();
$output = [];
// Chapters?
if ( $post_type === 'fcn_chapter' && fictioneer_get_field( 'fictioneer_chapter_story' ) && ! is_search() ) {
ob_start();
// Start HTML ---> ?>
<button class="mobile-menu__frame-button" data-frame-target="chapters">
<i class="fa-solid fa-caret-right mobile-menu__item-icon"></i> <?php _e( 'Chapters', 'fictioneer' ); ?>
</button>
<?php // <--- End HTML
$output['chapters'] = ob_get_clean();
}
// Chapters?
if ( $post_type === 'fcn_chapter' && fictioneer_get_field( 'fictioneer_chapter_story' ) && ! is_search() ) {
ob_start();
// Start HTML ---> ?>
<button class="mobile-menu__frame-button" data-frame-target="chapters">
<i class="fa-solid fa-caret-right mobile-menu__item-icon"></i> <?php _e( 'Chapters', 'fictioneer' ); ?>
</button>
<?php // <--- End HTML
$output['chapters'] = ob_get_clean();
}
// Bookmarks?
if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
ob_start();
// Start HTML ---> ?>
<button class="mobile-menu__frame-button" data-frame-target="bookmarks">
<i class="fa-solid fa-caret-right mobile-menu__item-icon"></i> <?php echo fcntr( 'bookmarks' ); ?>
</button>
<?php // <--- End HTML
$output['bookmarks'] = ob_get_clean();
}
// Bookmarks?
if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
ob_start();
// Start HTML ---> ?>
<button class="mobile-menu__frame-button" data-frame-target="bookmarks">
<i class="fa-solid fa-caret-right mobile-menu__item-icon"></i> <?php echo fcntr( 'bookmarks' ); ?>
</button>
<?php // <--- End HTML
$output['bookmarks'] = ob_get_clean();
}
// Follows?
if ( get_option( 'fictioneer_enable_follows' ) ) {
ob_start();
// Start HTML ---> ?>
<button class="mobile-menu__frame-button hide-if-logged-out follows-alert-number" data-frame-target="follows">
<i class="fa-solid fa-caret-right mobile-menu__item-icon"></i> <?php echo fcntr( 'follows' ); ?>
</button>
<?php // <--- End HTML
$output['follows'] = ob_get_clean();
}
// Follows?
if ( get_option( 'fictioneer_enable_follows' ) ) {
ob_start();
// Start HTML ---> ?>
<button class="mobile-menu__frame-button hide-if-logged-out follows-alert-number" data-frame-target="follows">
<i class="fa-solid fa-caret-right mobile-menu__item-icon"></i> <?php echo fcntr( 'follows' ); ?>
</button>
<?php // <--- End HTML
$output['follows'] = ob_get_clean();
}
// Render (if content)
if ( ! empty( $output ) ) {
echo '<div class="mobile-menu__panel mobile-menu__lists-panel">' . implode( '', $output ) . '</div>';
}
// Render (if content)
if ( ! empty( $output ) ) {
echo '<div class="mobile-menu__panel mobile-menu__lists-panel">' . implode( '', $output ) . '</div>';
}
}
add_action( 'fictioneer_mobile_menu_main_frame_panels', 'fictioneer_mobile_lists_panel', 20 );
@ -337,167 +321,165 @@ add_action( 'fictioneer_mobile_menu_main_frame_panels', 'fictioneer_mobile_lists
// MOBILE MENU USER NAVIGATION
// =============================================================================
if ( ! function_exists( 'fictioneer_mobile_user_menu' ) ) {
/**
* Adds the user menu to the mobile menu
*
* @since Fictioneer 5.0
*/
/**
* Adds the user menu to the mobile menu
*
* @since Fictioneer 5.0
*/
function fictioneer_mobile_user_menu() {
// Setup
$post_type = is_archive() ? 'archive' : get_post_type();
$bookmarks_link = fictioneer_get_assigned_page_link( 'fictioneer_bookmarks_page' );
$bookshelf_link = fictioneer_get_assigned_page_link( 'fictioneer_bookshelf_page' );
$discord_link = get_option( 'fictioneer_discord_invite_link' );
$can_checkmarks = get_option( 'fictioneer_enable_checkmarks' );
$can_follows = get_option( 'fictioneer_enable_follows' );
$can_reminders = get_option( 'fictioneer_enable_reminders' );
$profile_link = get_edit_profile_url();
$profile_page_id = intval( get_option( 'fictioneer_user_profile_page', -1 ) ?: -1 );
$output = [];
function fictioneer_mobile_user_menu() {
// Setup
$post_type = is_archive() ? 'archive' : get_post_type();
$bookmarks_link = fictioneer_get_assigned_page_link( 'fictioneer_bookmarks_page' );
$bookshelf_link = fictioneer_get_assigned_page_link( 'fictioneer_bookshelf_page' );
$discord_link = get_option( 'fictioneer_discord_invite_link' );
$can_checkmarks = get_option( 'fictioneer_enable_checkmarks' );
$can_follows = get_option( 'fictioneer_enable_follows' );
$can_reminders = get_option( 'fictioneer_enable_reminders' );
$profile_link = get_edit_profile_url();
$profile_page_id = intval( get_option( 'fictioneer_user_profile_page', -1 ) ?: -1 );
$output = [];
if ( $profile_page_id && $profile_page_id > 0 ) {
$profile_link = fictioneer_get_assigned_page_link( 'fictioneer_user_profile_page' );
}
// Build
if ( ! empty( $profile_link ) && fictioneer_show_auth_content() ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( $profile_link ); ?>" class="hide-if-logged-out">
<i class="fa-solid fa-circle-user mobile-menu__item-icon"></i>
<?php echo fcntr( 'account' ); ?>
</a>
<?php // <--- End HTML
$output['account'] = ob_get_clean();
}
if ( FICTIONEER_SHOW_SEARCH_IN_MENUS ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( home_url( '/?s=' ) ); ?>">
<i class="fa-solid fa-magnifying-glass mobile-menu__item-icon"></i>
<?php _e( 'Search', 'fictioneer' ); ?>
</a>
<?php // <--- End HTML
$output['search'] = ob_get_clean();
}
if ( $profile_page_id && $profile_page_id > 0 ) {
$profile_link = fictioneer_get_assigned_page_link( 'fictioneer_user_profile_page' );
}
// Build
if ( ! empty( $profile_link ) && fictioneer_show_auth_content() ) {
ob_start();
// Start HTML ---> ?>
<label for="modal-site-settings-toggle">
<i class="fa-solid fa-tools mobile-menu__item-icon"></i>
<?php echo fcntr( 'site_settings' ); ?>
<a href="<?php echo esc_url( $profile_link ); ?>" class="hide-if-logged-out">
<i class="fa-solid fa-circle-user mobile-menu__item-icon"></i>
<?php echo fcntr( 'account' ); ?>
</a>
<?php // <--- End HTML
$output['account'] = ob_get_clean();
}
if ( FICTIONEER_SHOW_SEARCH_IN_MENUS ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( home_url( '/?s=' ) ); ?>">
<i class="fa-solid fa-magnifying-glass mobile-menu__item-icon"></i>
<?php _e( 'Search', 'fictioneer' ); ?>
</a>
<?php // <--- End HTML
$output['search'] = ob_get_clean();
}
ob_start();
// Start HTML ---> ?>
<label for="modal-site-settings-toggle">
<i class="fa-solid fa-tools mobile-menu__item-icon"></i>
<?php echo fcntr( 'site_settings' ); ?>
</label>
<?php // <--- End HTML
$output['site_settings'] = ob_get_clean();
if ( ! empty( $discord_link ) ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( $discord_link ); ?>" rel="noopener noreferrer nofollow">
<i class="fa-brands fa-discord mobile-menu__item-icon"></i>
<?php _e( 'Discord', 'fictioneer' ) ?>
</a>
<?php // <--- End HTML
$output['discord'] = ob_get_clean();
}
if ( $bookshelf_link && fictioneer_show_auth_content() && ( $can_checkmarks || $can_follows || $can_reminders ) ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( $bookshelf_link ); ?>" rel="noopener noreferrer nofollow" class="hide-if-logged-out">
<i class="fa-solid fa-list mobile-menu__item-icon"></i>
<?php echo fcntr( 'bookshelf' ); ?>
</a>
<?php // <--- End HTML
$output['bookshelf'] = ob_get_clean();
}
if ( ! empty( $bookmarks_link ) && get_option( 'fictioneer_enable_bookmarks' ) ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( $bookmarks_link ); ?>" rel="noopener noreferrer nofollow">
<i class="fa-solid fa-bookmark mobile-menu__item-icon"></i>
<?php echo fcntr( 'bookmarks' ); ?>
</a>
<?php // <--- End HTML
$output['bookmarks'] = ob_get_clean();
}
if ( $post_type === 'fcn_chapter' && ! is_search() ) {
ob_start();
// Start HTML ---> ?>
<label for="modal-formatting-toggle">
<?php fictioneer_icon( 'font-settings', 'mobile-menu__item-icon' ); ?>
<?php echo fcntr( 'formatting' ); ?>
</label>
<?php // <--- End HTML
$output['site_settings'] = ob_get_clean();
if ( ! empty( $discord_link ) ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( $discord_link ); ?>" rel="noopener noreferrer nofollow">
<i class="fa-brands fa-discord mobile-menu__item-icon"></i>
<?php _e( 'Discord', 'fictioneer' ) ?>
</a>
<?php // <--- End HTML
$output['discord'] = ob_get_clean();
}
if ( $bookshelf_link && fictioneer_show_auth_content() && ( $can_checkmarks || $can_follows || $can_reminders ) ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( $bookshelf_link ); ?>" rel="noopener noreferrer nofollow" class="hide-if-logged-out">
<i class="fa-solid fa-list mobile-menu__item-icon"></i>
<?php echo fcntr( 'bookshelf' ); ?>
</a>
<?php // <--- End HTML
$output['bookshelf'] = ob_get_clean();
}
if ( ! empty( $bookmarks_link ) && get_option( 'fictioneer_enable_bookmarks' ) ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo esc_url( $bookmarks_link ); ?>" rel="noopener noreferrer nofollow">
<i class="fa-solid fa-bookmark mobile-menu__item-icon"></i>
<?php echo fcntr( 'bookmarks' ); ?>
</a>
<?php // <--- End HTML
$output['bookmarks'] = ob_get_clean();
}
if ( $post_type === 'fcn_chapter' && ! is_search() ) {
ob_start();
// Start HTML ---> ?>
<label for="modal-formatting-toggle">
<?php fictioneer_icon( 'font-settings', 'mobile-menu__item-icon' ); ?>
<?php echo fcntr( 'formatting' ); ?>
</label>
<?php // <--- End HTML
$output['formatting'] = ob_get_clean();
}
if (
$post_type === 'fcn_chapter' &&
! is_search() &&
comments_open() &&
! fictioneer_is_commenting_disabled() &&
! post_password_required()
) {
ob_start();
// Start HTML ---> ?>
<a id="mobile-menu-comment-jump" class="comments-toggle" rel="noopener noreferrer nofollow">
<i class="fa-solid fa-comments mobile-menu__item-icon"></i>
<?php echo fcntr( 'jump_to_comments' ); ?>
</a>
<?php // <--- End HTML
$output['comment_jump'] = ob_get_clean();
}
if (
$post_type === 'fcn_chapter' &&
! is_search() &&
get_option( 'fictioneer_enable_bookmarks' ) &&
! post_password_required()
) {
ob_start();
// Start HTML ---> ?>
<a id="mobile-menu-bookmark-jump" rel="noopener noreferrer nofollow" hidden>
<i class="fa-solid fa-bookmark mobile-menu__item-icon"></i>
<?php echo fcntr( 'jump_to_bookmark' ); ?>
</a>
<?php // <--- End HTML
$output['bookmark_jump'] = ob_get_clean();
}
if ( fictioneer_show_auth_content() ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo fictioneer_get_logout_url(); ?>" data-click="logout" rel="noopener noreferrer nofollow" class="hide-if-logged-out">
<?php fictioneer_icon( 'fa-logout', 'mobile-menu__item-icon', '', 'style="transform: translateY(-1px);"' ); ?>
<?php echo fcntr( 'logout' ); ?>
</a>
<?php // <--- End HTML
$output['logout'] = ob_get_clean();
}
if ( get_option( 'fictioneer_enable_oauth' ) && ! is_user_logged_in() ) {
ob_start();
// Start HTML ---> ?>
<label for="modal-login-toggle" class="hide-if-logged-in subscriber-login">
<?php fictioneer_icon( 'fa-login', 'mobile-menu__item-icon' ); ?>
<?php echo fcntr( 'login' ); ?>
</label>
<?php // <--- End HTML
$output['login'] = ob_get_clean();
}
// Apply filter
$output = apply_filters( 'fictioneer_filter_mobile_user_menu_items', $output );
// Return
echo '<div id="mobile-menu-user-panel" class="mobile-menu__panel">' . implode( '', $output ) . '</div>';
$output['formatting'] = ob_get_clean();
}
if (
$post_type === 'fcn_chapter' &&
! is_search() &&
comments_open() &&
! fictioneer_is_commenting_disabled() &&
! post_password_required()
) {
ob_start();
// Start HTML ---> ?>
<a id="mobile-menu-comment-jump" class="comments-toggle" rel="noopener noreferrer nofollow">
<i class="fa-solid fa-comments mobile-menu__item-icon"></i>
<?php echo fcntr( 'jump_to_comments' ); ?>
</a>
<?php // <--- End HTML
$output['comment_jump'] = ob_get_clean();
}
if (
$post_type === 'fcn_chapter' &&
! is_search() &&
get_option( 'fictioneer_enable_bookmarks' ) &&
! post_password_required()
) {
ob_start();
// Start HTML ---> ?>
<a id="mobile-menu-bookmark-jump" rel="noopener noreferrer nofollow" hidden>
<i class="fa-solid fa-bookmark mobile-menu__item-icon"></i>
<?php echo fcntr( 'jump_to_bookmark' ); ?>
</a>
<?php // <--- End HTML
$output['bookmark_jump'] = ob_get_clean();
}
if ( fictioneer_show_auth_content() ) {
ob_start();
// Start HTML ---> ?>
<a href="<?php echo fictioneer_get_logout_url(); ?>" data-click="logout" rel="noopener noreferrer nofollow" class="hide-if-logged-out">
<?php fictioneer_icon( 'fa-logout', 'mobile-menu__item-icon', '', 'style="transform: translateY(-1px);"' ); ?>
<?php echo fcntr( 'logout' ); ?>
</a>
<?php // <--- End HTML
$output['logout'] = ob_get_clean();
}
if ( get_option( 'fictioneer_enable_oauth' ) && ! is_user_logged_in() ) {
ob_start();
// Start HTML ---> ?>
<label for="modal-login-toggle" class="hide-if-logged-in subscriber-login">
<?php fictioneer_icon( 'fa-login', 'mobile-menu__item-icon' ); ?>
<?php echo fcntr( 'login' ); ?>
</label>
<?php // <--- End HTML
$output['login'] = ob_get_clean();
}
// Apply filter
$output = apply_filters( 'fictioneer_filter_mobile_user_menu_items', $output );
// Return
echo '<div id="mobile-menu-user-panel" class="mobile-menu__panel">' . implode( '', $output ) . '</div>';
}
add_action( 'fictioneer_mobile_menu_main_frame_panels', 'fictioneer_mobile_user_menu', 30 );

View File

@ -4,34 +4,32 @@
// ACCOUNT MODERATION MESSAGE SECTION
// =============================================================================
if ( ! function_exists( 'fictioneer_account_moderation_message' ) ) {
/**
* Outputs the HTML for the account moderation message section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
/**
* Outputs the HTML for the account moderation message section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
function fictioneer_account_moderation_message( $args ) {
// Setup
$message = get_the_author_meta( 'fictioneer_admin_moderation_message', $args['user']->ID );
function fictioneer_account_moderation_message( $args ) {
// Setup
$message = get_the_author_meta( 'fictioneer_admin_moderation_message', $args['user']->ID );
// Abort conditions
if ( empty( $message ) ) return;
// Abort conditions
if ( empty( $message ) ) return;
// Start HTML ---> ?>
<div class="profile__moderation-message profile__segment">
<div class="infobox polygon">
<p><?php echo $message; ?></p>
</div>
// Start HTML ---> ?>
<div class="profile__moderation-message profile__segment">
<div class="infobox polygon">
<p><?php echo $message; ?></p>
</div>
<?php // <--- End HTML
}
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_account_content', 'fictioneer_account_moderation_message', 5 );
@ -39,22 +37,20 @@ add_action( 'fictioneer_account_content', 'fictioneer_account_moderation_message
// ACCOUNT PROFILE SECTION
// =============================================================================
if ( ! function_exists( 'fictioneer_account_profile' ) ) {
/**
* Outputs the HTML for the account profile section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
/**
* Outputs the HTML for the account profile section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
function fictioneer_account_profile( $args ) {
get_template_part( 'partials/account/_profile', null, $args );
}
function fictioneer_account_profile( $args ) {
get_template_part( 'partials/account/_profile', null, $args );
}
add_action( 'fictioneer_account_content', 'fictioneer_account_profile', 10 );
@ -62,22 +58,20 @@ add_action( 'fictioneer_account_content', 'fictioneer_account_profile', 10 );
// ACCOUNT OAUTH BINDINGS SECTION
// =============================================================================
if ( ! function_exists( 'fictioneer_account_oauth' ) ) {
/**
* Outputs the HTML for the OAuth section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
/**
* Outputs the HTML for the OAuth section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
function fictioneer_account_oauth( $args ) {
get_template_part( 'partials/account/_oauth', null, $args );
}
function fictioneer_account_oauth( $args ) {
get_template_part( 'partials/account/_oauth', null, $args );
}
add_action( 'fictioneer_account_content', 'fictioneer_account_oauth', 20 );
@ -85,22 +79,20 @@ add_action( 'fictioneer_account_content', 'fictioneer_account_oauth', 20 );
// ACCOUNT DATA SECTION
// =============================================================================
if ( ! function_exists( 'fictioneer_account_data' ) ) {
/**
* Outputs the HTML for the data section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
/**
* Outputs the HTML for the data section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
function fictioneer_account_data( $args ) {
get_template_part( 'partials/account/_data', null, $args );
}
function fictioneer_account_data( $args ) {
get_template_part( 'partials/account/_data', null, $args );
}
add_action( 'fictioneer_account_content', 'fictioneer_account_data', 30 );
@ -108,22 +100,20 @@ add_action( 'fictioneer_account_content', 'fictioneer_account_data', 30 );
// ACCOUNT DISCUSSION SECTION
// =============================================================================
if ( ! function_exists( 'fictioneer_account_discussions' ) ) {
/**
* Outputs the HTML for the discussions section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
/**
* Outputs the HTML for the discussions section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
function fictioneer_account_discussions( $args ) {
get_template_part( 'partials/account/_discussions', null, $args );
}
function fictioneer_account_discussions( $args ) {
get_template_part( 'partials/account/_discussions', null, $args );
}
add_action( 'fictioneer_account_content', 'fictioneer_account_discussions', 40 );
@ -131,22 +121,20 @@ add_action( 'fictioneer_account_content', 'fictioneer_account_discussions', 40 )
// ACCOUNT DANGER ZONE SECTION
// =============================================================================
if ( ! function_exists( 'fictioneer_account_danger_zone' ) ) {
/**
* Outputs the HTML for the danger zone section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
/**
* Outputs the HTML for the danger zone section
*
* @since Fictioneer 5.0
*
* @param WP_User $args['user'] Current user.
* @param boolean $args['is_admin'] True if the user is an administrator.
* @param boolean $args['is_author'] True if the user is an author (by capabilities).
* @param boolean $args['is_editor'] True if the user is an editor.
* @param boolean $args['is_moderator'] True if the user is a moderator (by capabilities).
*/
function fictioneer_account_danger_zone( $args ) {
get_template_part( 'partials/account/_danger-zone', null, $args );
}
function fictioneer_account_danger_zone( $args ) {
get_template_part( 'partials/account/_danger-zone', null, $args );
}
if ( get_option( 'fictioneer_enable_subscriber_self_delete' ) ) {

View File

@ -4,79 +4,77 @@
// LIST OF ALL RECOMMENDATIONS
// =============================================================================
if ( ! function_exists( 'fictioneer_recommendations_list' ) ) {
/**
* Outputs the paginated card list for all recommendations
*
* @since 5.0
* @see recommendations.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['recommendations'] Paginated query of all published recommendations.
* @param string $args['queried_type'] The queried post type ('fcn_recommendation').
* @param array $args['query_args'] The query arguments used.
* @param string $args['order'] Current order. Default 'desc'.
* @param string $args['orderby'] Current orderby. Default 'modified'.
* @param int|string $args['ago'] Current date query argument part. Default 0.
*/
/**
* Outputs the paginated card list for all recommendations
*
* @since 5.0
* @see recommendations.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['recommendations'] Paginated query of all published recommendations.
* @param string $args['queried_type'] The queried post type ('fcn_recommendation').
* @param array $args['query_args'] The query arguments used.
* @param string $args['order'] Current order. Default 'desc'.
* @param string $args['orderby'] Current orderby. Default 'modified'.
* @param int|string $args['ago'] Current date query argument part. Default 0.
*/
function fictioneer_recommendations_list( $args ) {
// Start HTML ---> ?>
<section class="recommendations__list spacing-top">
<ul class="card-list" id="list-of-recommendations">
function fictioneer_recommendations_list( $args ) {
// Start HTML ---> ?>
<section class="recommendations__list spacing-top">
<ul class="card-list" id="list-of-recommendations">
<?php if ( $args['recommendations']->have_posts() ) : ?>
<?php
// Card arguments
$card_args = array(
'cache' => fictioneer_caching_active() && ! fictioneer_private_caching_active(),
'order' => $args['order'] ?? 'desc',
'orderby' => $args['orderby'] ?? 'modified',
'ago' => $args['ago'] ?? 0
);
// Filter card arguments
$card_args = apply_filters( 'fictioneer_filter_recommendations_card_args', $card_args, $args );
while ( $args['recommendations']->have_posts() ) {
$args['recommendations']->the_post();
get_template_part( 'partials/_card-recommendation', null, $card_args );
}
// Actions at end of results
do_action( 'fictioneer_recommendations_end_of_results', $args );
?>
<?php else: ?>
<?php do_action( 'fictioneer_recommendations_no_results', $args ); ?>
<li class="no-results">
<span><?php _e( 'No recommendations found.', 'fictioneer' ) ?></span>
</li>
<?php endif; wp_reset_postdata(); ?>
<?php if ( $args['recommendations']->have_posts() ) : ?>
<?php
$pag_args = array(
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $args['recommendations']->max_num_pages,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#list-of-recommendations'
// Card arguments
$card_args = array(
'cache' => fictioneer_caching_active() && ! fictioneer_private_caching_active(),
'order' => $args['order'] ?? 'desc',
'orderby' => $args['orderby'] ?? 'modified',
'ago' => $args['ago'] ?? 0
);
// Filter card arguments
$card_args = apply_filters( 'fictioneer_filter_recommendations_card_args', $card_args, $args );
while ( $args['recommendations']->have_posts() ) {
$args['recommendations']->the_post();
get_template_part( 'partials/_card-recommendation', null, $card_args );
}
// Actions at end of results
do_action( 'fictioneer_recommendations_end_of_results', $args );
?>
<?php if ( $args['recommendations']->max_num_pages > 1 ) : ?>
<li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li>
<?php endif; ?>
<?php else: ?>
</ul>
</section>
<?php // <--- End HTML
}
<?php do_action( 'fictioneer_recommendations_no_results', $args ); ?>
<li class="no-results">
<span><?php _e( 'No recommendations found.', 'fictioneer' ) ?></span>
</li>
<?php endif; wp_reset_postdata(); ?>
<?php
$pag_args = array(
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $args['recommendations']->max_num_pages,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#list-of-recommendations'
);
?>
<?php if ( $args['recommendations']->max_num_pages > 1 ) : ?>
<li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li>
<?php endif; ?>
</ul>
</section>
<?php // <--- End HTML
}
add_action( 'fictioneer_recommendations_after_content', 'fictioneer_recommendations_list', 30 );
@ -84,44 +82,42 @@ add_action( 'fictioneer_recommendations_after_content', 'fictioneer_recommendati
// RECOMMENDATION TAGS
// =============================================================================
if ( ! function_exists( 'fictioneer_recommendation_tags' ) ) {
/**
* Outputs the HTML for the recommendation page tags
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['recommendation'] The recommendation object.
* @param int $args['recommendation_id'] The recommendation post ID.
* @param int $args['title'] The safe recommendation title.
*/
/**
* Outputs the HTML for the recommendation page tags
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['recommendation'] The recommendation object.
* @param int $args['recommendation_id'] The recommendation post ID.
* @param int $args['title'] The safe recommendation title.
*/
function fictioneer_recommendation_tags( $args ) {
// Setup
$tag_args = [];
function fictioneer_recommendation_tags( $args ) {
// Setup
$tag_args = [];
// Show tags?
if ( ! get_option( 'fictioneer_hide_tags_on_pages' ) ) {
$tags = get_the_tags( $args['recommendation_id'] );
// Show tags?
if ( ! get_option( 'fictioneer_hide_tags_on_pages' ) ) {
$tags = get_the_tags( $args['recommendation_id'] );
if ( ! empty( $tags ) ) $tag_args[] = $tags;
}
// Show content warnings?
if ( ! get_option( 'fictioneer_hide_content_warnings_on_pages' ) ) {
$warnings = get_the_terms( $args['recommendation_id'], 'fcn_content_warning' );
if ( ! empty( $warnings ) ) $tag_args[] = $warnings;
}
// Abort conditions...
if ( empty( $tag_args ) ) return;
// Start HTML ---> ?>
<section class="recommendation__tags tag-group">
<?php echo fictioneer_get_taxonomy_pills( $tag_args, '_secondary' ); ?>
</section>
<?php // <--- End HTML
if ( ! empty( $tags ) ) $tag_args[] = $tags;
}
// Show content warnings?
if ( ! get_option( 'fictioneer_hide_content_warnings_on_pages' ) ) {
$warnings = get_the_terms( $args['recommendation_id'], 'fcn_content_warning' );
if ( ! empty( $warnings ) ) $tag_args[] = $warnings;
}
// Abort conditions...
if ( empty( $tag_args ) ) return;
// Start HTML ---> ?>
<section class="recommendation__tags tag-group">
<?php echo fictioneer_get_taxonomy_pills( $tag_args, '_secondary' ); ?>
</section>
<?php // <--- End HTML
}
add_action( 'fictioneer_recommendation_after_content', 'fictioneer_recommendation_tags', 10 );
@ -129,43 +125,41 @@ add_action( 'fictioneer_recommendation_after_content', 'fictioneer_recommendatio
// RECOMMENDATION LINKS
// =============================================================================
if ( ! function_exists( 'fictioneer_recommendation_links' ) ) {
/**
* Outputs the HTML for the recommendation page links
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['recommendation'] The recommendation object.
* @param int $args['recommendation_id'] The recommendation post ID.
* @param int $args['title'] The safe recommendation title.
*/
/**
* Outputs the HTML for the recommendation page links
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['recommendation'] The recommendation object.
* @param int $args['recommendation_id'] The recommendation post ID.
* @param int $args['title'] The safe recommendation title.
*/
function fictioneer_recommendation_links( $args ) {
// Setup
$links = fictioneer_get_field( 'fictioneer_recommendation_urls', $args['recommendation_id'] );
function fictioneer_recommendation_links( $args ) {
// Setup
$links = fictioneer_get_field( 'fictioneer_recommendation_urls', $args['recommendation_id'] );
// Abort conditions...
if ( ! $links ) return;
// Abort conditions...
if ( ! $links ) return;
// Prepare
$links = array_filter( explode( "\n", $links ) );
$tuples = [];
// Prepare
$links = array_filter( explode( "\n", $links ) );
$tuples = [];
foreach( $links as $tuple ) {
$tuple = explode( '|', $tuple );
$tuple = array_map( 'trim', $tuple );
$tuples[] = '<li><i class="fa-solid fa-external-link-square-alt"></i><a href="' . esc_url( $tuple[1] ) . '" class="link" rel="noopener" target="_blank">' . wp_strip_all_tags( $tuple[0] ) . '</a></li>';
}
// Start HTML ---> ?>
<div class="recommendation__read-on">
<h5><?php _e( 'Read on', 'fictioneer' ) ?></h5>
<div>
<ul class="recommendation__list"><?php echo implode( '', $tuples ); ?></ul>
</div>
</div>
<?php // <--- End HTML
foreach( $links as $tuple ) {
$tuple = explode( '|', $tuple );
$tuple = array_map( 'trim', $tuple );
$tuples[] = '<li><i class="fa-solid fa-external-link-square-alt"></i><a href="' . esc_url( $tuple[1] ) . '" class="link" rel="noopener" target="_blank">' . wp_strip_all_tags( $tuple[0] ) . '</a></li>';
}
// Start HTML ---> ?>
<div class="recommendation__read-on">
<h5><?php _e( 'Read on', 'fictioneer' ) ?></h5>
<div>
<ul class="recommendation__list"><?php echo implode( '', $tuples ); ?></ul>
</div>
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_recommendation_after_content', 'fictioneer_recommendation_links', 20 );
@ -173,48 +167,46 @@ add_action( 'fictioneer_recommendation_after_content', 'fictioneer_recommendatio
// RECOMMENDATION AUTHOR LINKS
// =============================================================================
if ( ! function_exists( 'fictioneer_recommendation_support_links' ) ) {
/**
* Outputs the HTML for the recommendation page author links
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['recommendation'] The recommendation object.
* @param int $args['recommendation_id'] The recommendation post ID.
* @param int $args['title'] The safe recommendation title.
*/
/**
* Outputs the HTML for the recommendation page author links
*
* @since Fictioneer 5.0
*
* @param WP_Post $args['recommendation'] The recommendation object.
* @param int $args['recommendation_id'] The recommendation post ID.
* @param int $args['title'] The safe recommendation title.
*/
function fictioneer_recommendation_support_links( $args ) {
// Setup
$links = fictioneer_get_field( 'fictioneer_recommendation_support', $args['recommendation_id'] );
function fictioneer_recommendation_support_links( $args ) {
// Setup
$links = fictioneer_get_field( 'fictioneer_recommendation_support', $args['recommendation_id'] );
// Abort conditions...
if ( ! $links ) return;
// Abort conditions...
if ( ! $links ) return;
// Prepare
$links = array_filter( explode( "\n", $links ) );
$tuples = [];
// Prepare
$links = array_filter( explode( "\n", $links ) );
$tuples = [];
foreach( $links as $tuple ) {
$tuple = explode( '|', $tuple );
$tuple = array_map( 'trim', $tuple );
$tuples[] = '<li><i class="fa-solid fa-external-link-square-alt"></i><a href="' . esc_url( $tuple[1] ) . '" class="link" rel="noopener" target="_blank">' . wp_strip_all_tags( $tuple[0] ) . '</a></li>';
}
// Start HTML ---> ?>
<div class="recommendation__support">
<h5><?php
printf(
_x( 'Support <em>%s</em>', 'Support _author_', 'fictioneer' ),
fictioneer_get_field( 'fictioneer_recommendation_author', $args['recommendation_id'] )
)
?></h5>
<div>
<ul class="recommendation__list"><?php echo implode( '', $tuples ); ?></ul>
</div>
</div>
<?php // <--- End HTML
foreach( $links as $tuple ) {
$tuple = explode( '|', $tuple );
$tuple = array_map( 'trim', $tuple );
$tuples[] = '<li><i class="fa-solid fa-external-link-square-alt"></i><a href="' . esc_url( $tuple[1] ) . '" class="link" rel="noopener" target="_blank">' . wp_strip_all_tags( $tuple[0] ) . '</a></li>';
}
// Start HTML ---> ?>
<div class="recommendation__support">
<h5><?php
printf(
_x( 'Support <em>%s</em>', 'Support _author_', 'fictioneer' ),
fictioneer_get_field( 'fictioneer_recommendation_author', $args['recommendation_id'] )
)
?></h5>
<div>
<ul class="recommendation__list"><?php echo implode( '', $tuples ); ?></ul>
</div>
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_recommendation_after_content', 'fictioneer_recommendation_support_links', 30 );

View File

@ -4,68 +4,66 @@
// STATISTICS FOR ALL STORIES
// =============================================================================
if ( ! function_exists( 'fictioneer_stories_statistics' ) ) {
/**
* Outputs the statistics section for all stories
*
* Renders a statistics block with the number of published stories as well as
* word count, comments, and the estimated reading time for all stories. The
* reading time divisor can be changed under Fictioneer > General (default: 200).
*
* @since 5.0
* @see stories.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['stories'] Paginated query of all published stories.
* @param string $args['queried_type'] The queried post type ('fcn_story').
*/
/**
* Outputs the statistics section for all stories
*
* Renders a statistics block with the number of published stories as well as
* word count, comments, and the estimated reading time for all stories. The
* reading time divisor can be changed under Fictioneer > General (default: 200).
*
* @since 5.0
* @see stories.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['stories'] Paginated query of all published stories.
* @param string $args['queried_type'] The queried post type ('fcn_story').
*/
function fictioneer_stories_statistics( $args ) {
// Setup
$words = fictioneer_get_stories_total_word_count();
$statistics = array(
'stories' => array(
'label' => __( 'Stories', 'fictioneer' ),
'content' => number_format_i18n( wp_count_posts( 'fcn_story' )->publish )
),
'words' => array(
'label' => __( 'Words', 'fictioneer' ),
'content' => fictioneer_shorten_number( $words )
),
'comments' => array(
'label' => __( 'Comments', 'fictioneer' ),
'content' => number_format_i18n(
get_comments(
array(
'post_type' => 'fcn_chapter',
'status' => 1,
'count' => true,
'update_comment_meta_cache' => false
)
function fictioneer_stories_statistics( $args ) {
// Setup
$words = fictioneer_get_stories_total_word_count();
$statistics = array(
'stories' => array(
'label' => __( 'Stories', 'fictioneer' ),
'content' => number_format_i18n( wp_count_posts( 'fcn_story' )->publish )
),
'words' => array(
'label' => __( 'Words', 'fictioneer' ),
'content' => fictioneer_shorten_number( $words )
),
'comments' => array(
'label' => __( 'Comments', 'fictioneer' ),
'content' => number_format_i18n(
get_comments(
array(
'post_type' => 'fcn_chapter',
'status' => 1,
'count' => true,
'update_comment_meta_cache' => false
)
)
),
'reading' => array(
'label' => __( 'Reading', 'fictioneer' ),
'content' => fictioneer_get_reading_time_nodes( $words )
),
);
)
),
'reading' => array(
'label' => __( 'Reading', 'fictioneer' ),
'content' => fictioneer_get_reading_time_nodes( $words )
),
);
// Apply filter
$statistics = apply_filters( 'fictioneer_filter_stories_statistics', $statistics, $args );
// Apply filter
$statistics = apply_filters( 'fictioneer_filter_stories_statistics', $statistics, $args );
// Start HTML ---> ?>
<div class="stories__statistics statistics spacing-top">
<?php foreach ( $statistics as $stat ) : ?>
<div class="statistics__inline-stat">
<strong><?php echo $stat['label']; ?></strong>
<span><?php echo $stat['content']; ?></span>
</div>
<?php endforeach; ?>
</div>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<div class="stories__statistics statistics spacing-top">
<?php foreach ( $statistics as $stat ) : ?>
<div class="statistics__inline-stat">
<strong><?php echo $stat['label']; ?></strong>
<span><?php echo $stat['content']; ?></span>
</div>
<?php endforeach; ?>
</div>
<?php // <--- End HTML
}
add_action( 'fictioneer_stories_after_content', 'fictioneer_stories_statistics', 10 );
@ -73,84 +71,82 @@ add_action( 'fictioneer_stories_after_content', 'fictioneer_stories_statistics',
// LIST OF ALL STORIES
// =============================================================================
if ( ! function_exists( 'fictioneer_stories_list' ) ) {
/**
* Outputs the paginated card list for all stories
*
* @since 5.0
* @see stories.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['stories'] Paginated query of all published stories.
* @param string $args['queried_type'] The queried post type ('fcn_story').
* @param array $args['query_args'] The query arguments used.
* @param string $args['order'] Current order. Default 'desc'.
* @param string $args['orderby'] Current orderby. Default 'modified'.
* @param int|string $args['ago'] Current date query argument part. Default 0.
*/
/**
* Outputs the paginated card list for all stories
*
* @since 5.0
* @see stories.php
*
* @param int $args['current_page'] Current page number of pagination or 1.
* @param int $args['post_id'] The post ID.
* @param WP_Query $args['stories'] Paginated query of all published stories.
* @param string $args['queried_type'] The queried post type ('fcn_story').
* @param array $args['query_args'] The query arguments used.
* @param string $args['order'] Current order. Default 'desc'.
* @param string $args['orderby'] Current orderby. Default 'modified'.
* @param int|string $args['ago'] Current date query argument part. Default 0.
*/
function fictioneer_stories_list( $args ) {
// Start HTML ---> ?>
<section class="stories__list spacing-top">
<ul class="card-list" id="list-of-stories">
function fictioneer_stories_list( $args ) {
// Start HTML ---> ?>
<section class="stories__list spacing-top">
<ul class="card-list" id="list-of-stories">
<?php if ( $args['stories']->have_posts() ) : ?>
<?php
// Card arguments
$card_args = array(
'cache' => fictioneer_caching_active() && ! fictioneer_private_caching_active(),
'order' => $args['order'] ?? 'desc',
'orderby' => $args['orderby'] ?? 'modified',
'ago' => $args['ago'] ?? 0
);
// Filter card arguments
$card_args = apply_filters( 'fictioneer_filter_stories_card_args', $card_args, $args );
while ( $args['stories']->have_posts() ) {
$args['stories']->the_post();
if ( fictioneer_get_field( 'fictioneer_story_hidden' ) ) {
get_template_part( 'partials/_card-hidden', null, $card_args );
} else {
get_template_part( 'partials/_card-story', null, $card_args );
}
}
// Actions at end of results
do_action( 'fictioneer_stories_end_of_results', $args );
?>
<?php else : ?>
<?php do_action( 'fictioneer_stories_no_results', $args ); ?>
<li class="no-results">
<span><?php _e( 'No stories found.', 'fictioneer' ) ?></span>
</li>
<?php endif; wp_reset_postdata(); ?>
<?php if ( $args['stories']->have_posts() ) : ?>
<?php
$pag_args = array(
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $args['stories']->max_num_pages,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#list-of-stories'
// Card arguments
$card_args = array(
'cache' => fictioneer_caching_active() && ! fictioneer_private_caching_active(),
'order' => $args['order'] ?? 'desc',
'orderby' => $args['orderby'] ?? 'modified',
'ago' => $args['ago'] ?? 0
);
// Filter card arguments
$card_args = apply_filters( 'fictioneer_filter_stories_card_args', $card_args, $args );
while ( $args['stories']->have_posts() ) {
$args['stories']->the_post();
if ( fictioneer_get_field( 'fictioneer_story_hidden' ) ) {
get_template_part( 'partials/_card-hidden', null, $card_args );
} else {
get_template_part( 'partials/_card-story', null, $card_args );
}
}
// Actions at end of results
do_action( 'fictioneer_stories_end_of_results', $args );
?>
<?php if ( $args['stories']->max_num_pages > 1 ) : ?>
<li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li>
<?php endif; ?>
<?php else : ?>
</ul>
</section>
<?php // <--- End HTML
}
<?php do_action( 'fictioneer_stories_no_results', $args ); ?>
<li class="no-results">
<span><?php _e( 'No stories found.', 'fictioneer' ) ?></span>
</li>
<?php endif; wp_reset_postdata(); ?>
<?php
$pag_args = array(
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $args['stories']->max_num_pages,
'prev_text' => fcntr( 'previous' ),
'next_text' => fcntr( 'next' ),
'add_fragment' => '#list-of-stories'
);
?>
<?php if ( $args['stories']->max_num_pages > 1 ) : ?>
<li class="pagination"><?php echo fictioneer_paginate_links( $pag_args ); ?></li>
<?php endif; ?>
</ul>
</section>
<?php // <--- End HTML
}
add_action( 'fictioneer_stories_after_content', 'fictioneer_stories_list', 30 );
@ -158,29 +154,27 @@ add_action( 'fictioneer_stories_after_content', 'fictioneer_stories_list', 30 );
// STORY COPYRIGHT NOTICE
// =============================================================================
if ( ! function_exists( 'fictioneer_story_copyright_notice' ) ) {
/**
* Outputs the HTML for the story page copyright notice
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
/**
* Outputs the HTML for the story page copyright notice
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
function fictioneer_story_copyright_notice( $args ) {
// Setup
$copyright_notice = fictioneer_get_field( 'fictioneer_story_copyright_notice', $args['story_id'] );
function fictioneer_story_copyright_notice( $args ) {
// Setup
$copyright_notice = fictioneer_get_field( 'fictioneer_story_copyright_notice', $args['story_id'] );
// Abort conditions...
if ( empty( $copyright_notice ) ) return;
// Abort conditions...
if ( empty( $copyright_notice ) ) return;
// Start HTML ---> ?>
<section class="story__copyright-notice padding-left padding-right">
<i class="fa-regular fa-copyright"></i> <?php echo $copyright_notice; ?>
</section>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<section class="story__copyright-notice padding-left padding-right">
<i class="fa-regular fa-copyright"></i> <?php echo $copyright_notice; ?>
</section>
<?php // <--- End HTML
}
add_action( 'fictioneer_story_after_content', 'fictioneer_story_copyright_notice', 10 );
@ -188,33 +182,31 @@ add_action( 'fictioneer_story_after_content', 'fictioneer_story_copyright_notice
// STORY TAGS & WARNINGS
// =============================================================================
if ( ! function_exists( 'fictioneer_story_tags_and_warnings' ) ) {
/**
* Outputs the HTML for the story page tags and warnings
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
/**
* Outputs the HTML for the story page tags and warnings
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
function fictioneer_story_tags_and_warnings( $args ) {
// Abort conditions...
$tags_shown = $args['story_data']['tags'] && ! get_option( 'fictioneer_hide_tags_on_pages' ) && ! fictioneer_get_field( 'fictioneer_story_no_tags' );;
$warnings_shown = $args['story_data']['warnings'] && ! get_option( 'fictioneer_hide_content_warnings_on_pages' );
if ( ! $tags_shown && ! $warnings_shown ) return;
function fictioneer_story_tags_and_warnings( $args ) {
// Abort conditions...
$tags_shown = $args['story_data']['tags'] && ! get_option( 'fictioneer_hide_tags_on_pages' ) && ! fictioneer_get_field( 'fictioneer_story_no_tags' );;
$warnings_shown = $args['story_data']['warnings'] && ! get_option( 'fictioneer_hide_content_warnings_on_pages' );
if ( ! $tags_shown && ! $warnings_shown ) return;
// Setup
$tag_args = [];
if ( $tags_shown ) $tag_args[] = $args['story_data']['tags'];
if ( $warnings_shown ) $tag_args[] = $args['story_data']['warnings'];
// Setup
$tag_args = [];
if ( $tags_shown ) $tag_args[] = $args['story_data']['tags'];
if ( $warnings_shown ) $tag_args[] = $args['story_data']['warnings'];
// Start HTML ---> ?>
<section class="story__tags-and-warnings tag-group padding-left padding-right"><?php
echo fictioneer_get_taxonomy_pills( $tag_args, '_secondary' );
?></section>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<section class="story__tags-and-warnings tag-group padding-left padding-right"><?php
echo fictioneer_get_taxonomy_pills( $tag_args, '_secondary' );
?></section>
<?php // <--- End HTML
}
add_action( 'fictioneer_story_after_content', 'fictioneer_story_tags_and_warnings', 20 );
@ -222,27 +214,25 @@ add_action( 'fictioneer_story_after_content', 'fictioneer_story_tags_and_warning
// STORY ACTIONS ROW
// =============================================================================
if ( ! function_exists( 'fictioneer_story_actions' ) ) {
/**
* Outputs the HTML for the story page actions row
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
/**
* Outputs the HTML for the story page actions row
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
function fictioneer_story_actions( $args ) {
// Abort conditions...
if ( post_password_required() ) return;
function fictioneer_story_actions( $args ) {
// Abort conditions...
if ( post_password_required() ) return;
// Start HTML ---> ?>
<section class="story__after-summary padding-left padding-right">
<?php get_template_part( 'partials/_share-buttons' ); ?>
<div class="story__actions"><?php echo fictioneer_get_story_buttons( $args ); ?></div>
</section>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<section class="story__after-summary padding-left padding-right">
<?php get_template_part( 'partials/_share-buttons' ); ?>
<div class="story__actions"><?php echo fictioneer_get_story_buttons( $args ); ?></div>
</section>
<?php // <--- End HTML
}
add_action( 'fictioneer_story_after_content', 'fictioneer_story_actions', 30 );
@ -250,23 +240,21 @@ add_action( 'fictioneer_story_after_content', 'fictioneer_story_actions', 30 );
// STORY CHAPTERS
// =============================================================================
if ( ! function_exists( 'fictioneer_story_content' ) ) {
/**
* Outputs the HTML for the story page actions row
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
/**
* Outputs the HTML for the story page actions row
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
function fictioneer_story_content( $args ) {
// Abort conditions...
if ( post_password_required() ) return;
function fictioneer_story_content( $args ) {
// Abort conditions...
if ( post_password_required() ) return;
// Render partial
get_template_part( 'partials/_story-content', null, $args );
}
// Render partial
get_template_part( 'partials/_story-content', null, $args );
}
add_action( 'fictioneer_story_after_content', 'fictioneer_story_content', 40 );
@ -274,23 +262,21 @@ add_action( 'fictioneer_story_after_content', 'fictioneer_story_content', 40 );
// STORY COMMENTS
// =============================================================================
if ( ! function_exists( 'fictioneer_story_comment' ) ) {
/**
* Outputs the HTML for the story page comments
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
/**
* Outputs the HTML for the story page comments
*
* @since Fictioneer 5.0
*
* @param array $args['story_data'] Collection of story data.
* @param int $args['story_id'] The story post ID.
*/
function fictioneer_story_comment( $args ) {
// Abort conditions...
if ( post_password_required() ) return;
function fictioneer_story_comment( $args ) {
// Abort conditions...
if ( post_password_required() ) return;
// Render partial
get_template_part( 'partials/_story-comments', null, $args );
}
// Render partial
get_template_part( 'partials/_story-comments', null, $args );
}
add_action( 'fictioneer_story_after_article', 'fictioneer_story_comment', 10 );

View File

@ -4,35 +4,35 @@
// REFRESH CHAPTER SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_chapter_schema' ) ) {
/**
* Refresh chapter schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh chapter schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_chapter_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
if ( $post->post_type !== 'fcn_chapter' ) return;
// Setup
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post_id );
// Rebuild schema(s)
fictioneer_build_chapter_schema( $post_id );
if ( ! empty( $story_id ) ) fictioneer_build_story_schema( $story_id );
function fictioneer_refresh_chapter_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
if ( $post->post_type !== 'fcn_chapter' ) {
return;
}
// Setup
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $post_id );
// Rebuild schema(s)
fictioneer_build_chapter_schema( $post_id );
if ( ! empty( $story_id ) ) fictioneer_build_story_schema( $story_id );
}
add_action( 'save_post', 'fictioneer_refresh_chapter_schema', 20, 2 );

View File

@ -4,44 +4,46 @@
// REFRESH CHAPTERS SUMMARY SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_chapters_schema' ) ) {
/**
* Refresh chapters summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh chapters summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_chapters_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
function fictioneer_refresh_chapters_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
$sub_update = in_array( $post->post_type, ['fcn_chapter', 'fcn_collection'] );
if ( get_page_template_slug() != 'chapters.php' && ! $sub_update ) return;
// Check what was updated
if (
get_page_template_slug() != 'chapters.php' &&
! in_array( $post->post_type, ['fcn_chapter', 'fcn_collection'] )
) {
return;
}
// Get all pages with the chapters template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'chapters.php'
)
);
// Get all pages with the chapters template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'chapters.php'
)
);
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_chapters_schema( $page->ID );
}
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_chapters_schema( $page->ID );
}
}
}

View File

@ -4,44 +4,46 @@
// REFRESH COLLECTIONS SUMMARY SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_collections_schema' ) ) {
/**
* Refresh collections summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh collections summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_collections_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
function fictioneer_refresh_collections_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
$sub_update = in_array( $post->post_type, ['fcn_collection', 'fcn_story', 'fcn_chapter', 'fcn_recommendation', 'post'] );
if ( get_page_template_slug() != 'collections.php' && ! $sub_update ) return;
// Check what was updated
if (
get_page_template_slug() != 'collections.php' &&
! in_array( $post->post_type, ['fcn_collection', 'fcn_story', 'fcn_chapter', 'fcn_recommendation', 'post'] )
) {
return;
}
// Get all pages with the collections template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'collections.php'
)
);
// Get all pages with the collections template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'collections.php'
)
);
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_collections_schema( $page->ID );
}
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_collections_schema( $page->ID );
}
}
}

View File

@ -4,31 +4,31 @@
// REFRESH POST SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_post_schema' ) ) {
/**
* Refresh post schema
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh post schema
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_post_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
if ( $post->post_type !== 'post' ) return;
// Rebuild
fictioneer_build_post_schema( $post_id );
function fictioneer_refresh_post_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
if ( $post->post_type !== 'post' ) {
return;
}
// Rebuild
fictioneer_build_post_schema( $post_id );
}
add_action( 'save_post', 'fictioneer_refresh_post_schema', 20, 2 );

View File

@ -4,31 +4,31 @@
// REFRESH RECOMMENDATION SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_recommendation_schema' ) ) {
/**
* Refresh recommendation schema
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh recommendation schema
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_recommendation_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
if ( $post->post_type !== 'fcn_recommendation' ) return;
// Rebuild
fictioneer_build_recommendation_schema( $post_id );
function fictioneer_refresh_recommendation_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
if ( $post->post_type !== 'fcn_recommendation' ) {
return;
}
// Rebuild
fictioneer_build_recommendation_schema( $post_id );
}
add_action( 'save_post', 'fictioneer_refresh_recommendation_schema', 20, 2 );

View File

@ -4,44 +4,46 @@
// REFRESH RECOMMENDATIONS SUMMARY SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_recommendations_schema' ) ) {
/**
* Refresh recommendations summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh recommendations summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_recommendations_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
function fictioneer_refresh_recommendations_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
$sub_update = in_array( $post->post_type, ['fcn_recommendation', 'fcn_collection'] );
if ( get_page_template_slug() != 'recommendations.php' && ! $sub_update ) return;
// Check what was updated
if (
get_page_template_slug() != 'recommendations.php' &&
! in_array( $post->post_type, ['fcn_recommendation', 'fcn_collection'] )
) {
return;
}
// Get all pages with the recommendations template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'recommendations.php'
)
);
// Get all pages with the recommendations template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'recommendations.php'
)
);
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_recommendations_schema( $page->ID );
}
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_recommendations_schema( $page->ID );
}
}
}

View File

@ -4,44 +4,46 @@
// REFRESH STORIES SUMMARY SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_stories_schema' ) ) {
/**
* Refresh stories summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh stories summary schemas
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_stories_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
function fictioneer_refresh_stories_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
$sub_update = in_array( $post->post_type, ['fcn_story', 'fcn_collection'] );
if ( get_page_template_slug() != 'stories.php' && ! $sub_update ) return;
// Check what was updated
if (
get_page_template_slug() != 'stories.php' &&
! in_array( $post->post_type, ['fcn_story', 'fcn_collection'] )
) {
return;
}
// Get all pages with the stories template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'stories.php'
)
);
// Get all pages with the stories template
$pages = get_posts(
array(
'post_type' => 'page',
'numberposts' => -1,
'meta_key' => '_wp_page_template',
'meta_value' => 'stories.php'
)
);
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_stories_schema( $page->ID );
}
// Rebuild schemas
if ( $pages ) {
foreach ( $pages as $page ) {
fictioneer_build_stories_schema( $page->ID );
}
}
}

View File

@ -4,39 +4,39 @@
// REFRESH STORY SCHEMA
// =============================================================================
if ( ! function_exists( 'fictioneer_refresh_story_schema' ) ) {
/**
* Refresh story schema
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
/**
* Refresh story schema
*
* "There are only two hard things in Computer Science: cache invalidation and
* naming things" -- Phil Karlton.
*
* @since Fictioneer 4.0
*
* @param int $post_id The ID of the saved post.
* @param WP_Post $post The saved post object.
*/
function fictioneer_refresh_story_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
function fictioneer_refresh_story_schema( $post_id, $post ) {
// Prevent multi-fire
if ( fictioneer_multi_save_guard( $post_id ) ) {
return;
}
// Check what was updated
if ( $post->post_type !== 'fcn_story' ) return;
// Check what was updated
if ( $post->post_type !== 'fcn_story' ) {
return;
}
// Rebuild schema(s)
fictioneer_build_story_schema( $post_id );
// Rebuild schema(s)
fictioneer_build_story_schema( $post_id );
// Get chapters of story
$chapters = fictioneer_get_field( 'fictioneer_story_chapters', $post_id );
// Get chapters of story
$chapters = fictioneer_get_field( 'fictioneer_story_chapters', $post_id );
// Rebuild chapter schemas (if any)
if ( ! empty( $chapters ) ) {
foreach ( $chapters as $chapter_id ) {
fictioneer_build_chapter_schema( $chapter_id );
}
// Rebuild chapter schemas (if any)
if ( ! empty( $chapters ) ) {
foreach ( $chapters as $chapter_id ) {
fictioneer_build_chapter_schema( $chapter_id );
}
}
}

View File

@ -647,74 +647,72 @@ add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_fields_d
* currently editing the profile!
*/
if ( ! function_exists( 'fictioneer_admin_profile_moderation' ) ) {
function fictioneer_admin_profile_moderation( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
$editing_user_is_moderator = fictioneer_is_moderator( get_current_user_id() );
function fictioneer_admin_profile_moderation( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
$editing_user_is_moderator = fictioneer_is_moderator( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin && ! $editing_user_is_moderator ) return;
// Abort conditions...
if ( ! $editing_user_is_admin && ! $editing_user_is_moderator ) return;
// Start HTML ---> ?>
<tr class="user-moderation-flags-wrap">
<th><?php _e( 'Moderation Flags', 'fictioneer' ) ?></th>
<td>
<fieldset>
<div>
<label for="fictioneer_admin_disable_avatar" class="checkbox-group">
<input name="fictioneer_admin_disable_avatar" type="checkbox" id="fictioneer_admin_disable_avatar" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_avatar', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable user avatar', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_reporting" class="checkbox-group">
<input name="fictioneer_admin_disable_reporting" type="checkbox" id="fictioneer_admin_disable_reporting" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_reporting', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable reporting capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_renaming" class="checkbox-group">
<input name="fictioneer_admin_disable_renaming" type="checkbox" id="fictioneer_admin_disable_renaming" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_renaming', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable renaming capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_commenting" class="checkbox-group">
<input name="fictioneer_admin_disable_commenting" type="checkbox" id="fictioneer_admin_disable_commenting" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_commenting', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable commenting capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_editing" class="checkbox-group">
<input name="fictioneer_admin_disable_editing" type="checkbox" id="fictioneer_admin_disable_editing" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_editing', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable comment editing capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_comment_notifications" class="checkbox-group">
<input name="fictioneer_admin_disable_comment_notifications" type="checkbox" id="fictioneer_admin_disable_comment_notifications" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_comment_notifications', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable comment reply notifications', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_always_moderate_comments" class="checkbox-group">
<input name="fictioneer_admin_always_moderate_comments" type="checkbox" id="fictioneer_admin_always_moderate_comments" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_always_moderate_comments', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Always hold comments for moderation', 'fictioneer' ) ?></span>
</label>
</div>
</fieldset>
</td>
</tr>
<tr class="user-moderation-message-wrap">
<th><label for="fictioneer_admin_moderation_message"><?php _e( 'Moderation Message', 'fictioneer' ) ?></label></th>
<td>
<textarea name="fictioneer_admin_moderation_message" id="fictioneer_admin_moderation_message" rows="8" cols="30"><?php echo esc_attr( get_the_author_meta( 'fictioneer_admin_moderation_message', $profile_user->ID ) ); ?></textarea>
<p class="description"><?php _e( 'Custom message in the user profile, which may be a nice thing as well.', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<tr class="user-moderation-flags-wrap">
<th><?php _e( 'Moderation Flags', 'fictioneer' ) ?></th>
<td>
<fieldset>
<div>
<label for="fictioneer_admin_disable_avatar" class="checkbox-group">
<input name="fictioneer_admin_disable_avatar" type="checkbox" id="fictioneer_admin_disable_avatar" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_avatar', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable user avatar', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_reporting" class="checkbox-group">
<input name="fictioneer_admin_disable_reporting" type="checkbox" id="fictioneer_admin_disable_reporting" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_reporting', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable reporting capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_renaming" class="checkbox-group">
<input name="fictioneer_admin_disable_renaming" type="checkbox" id="fictioneer_admin_disable_renaming" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_renaming', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable renaming capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_commenting" class="checkbox-group">
<input name="fictioneer_admin_disable_commenting" type="checkbox" id="fictioneer_admin_disable_commenting" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_commenting', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable commenting capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_editing" class="checkbox-group">
<input name="fictioneer_admin_disable_editing" type="checkbox" id="fictioneer_admin_disable_editing" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_editing', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable comment editing capability', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_disable_comment_notifications" class="checkbox-group">
<input name="fictioneer_admin_disable_comment_notifications" type="checkbox" id="fictioneer_admin_disable_comment_notifications" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_disable_comment_notifications', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Disable comment reply notifications', 'fictioneer' ) ?></span>
</label>
</div>
<div>
<label for="fictioneer_admin_always_moderate_comments" class="checkbox-group">
<input name="fictioneer_admin_always_moderate_comments" type="checkbox" id="fictioneer_admin_always_moderate_comments" <?php echo checked( 1, get_the_author_meta( 'fictioneer_admin_always_moderate_comments', $profile_user->ID ), false ); ?> value="1">
<span><?php _e( 'Always hold comments for moderation', 'fictioneer' ) ?></span>
</label>
</div>
</fieldset>
</td>
</tr>
<tr class="user-moderation-message-wrap">
<th><label for="fictioneer_admin_moderation_message"><?php _e( 'Moderation Message', 'fictioneer' ) ?></label></th>
<td>
<textarea name="fictioneer_admin_moderation_message" id="fictioneer_admin_moderation_message" rows="8" cols="30"><?php echo esc_attr( get_the_author_meta( 'fictioneer_admin_moderation_message', $profile_user->ID ) ); ?></textarea>
<p class="description"><?php _e( 'Custom message in the user profile, which may be a nice thing as well.', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_moderation', 10 );
@ -731,80 +729,78 @@ add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_moderati
* currently editing the profile!
*/
if ( ! function_exists( 'fictioneer_admin_profile_author' ) ) {
function fictioneer_admin_profile_author( $profile_user ) {
// Setup
$is_owner = $profile_user->ID === get_current_user_id();
$profile_user_is_author = fictioneer_is_author( $profile_user->ID );
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
function fictioneer_admin_profile_author( $profile_user ) {
// Setup
$is_owner = $profile_user->ID === get_current_user_id();
$profile_user_is_author = fictioneer_is_author( $profile_user->ID );
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $profile_user_is_author ) return;
if ( ! $is_owner && ! $editing_user_is_admin ) return;
// Abort conditions...
if ( ! $profile_user_is_author ) return;
if ( ! $is_owner && ! $editing_user_is_admin ) return;
// Has pages?
$profile_user_has_pages = get_pages(
array(
'authors' => $profile_user->ID,
'number' => 1
)
);
// Has pages?
$profile_user_has_pages = get_pages(
array(
'authors' => $profile_user->ID,
'number' => 1
)
);
// Start HTML ---> ?>
<tr class="user-author-page-wrap">
<th><label for="fictioneer_author_page"><?php _e( 'Author Page', 'fictioneer' ) ?></label></th>
<td>
<?php if ( $profile_user_has_pages ) : ?>
<?php
wp_dropdown_pages(
array(
'name' => 'fictioneer_author_page',
'id' => 'fictioneer_author_page',
'option_none_value' => __( 'None', 'fictioneer' ),
'show_option_no_change' => __( 'None', 'fictioneer' ),
'selected' => get_the_author_meta( 'fictioneer_author_page', $profile_user->ID ),
'authors' => $profile_user->ID
)
);
?>
<?php else : ?>
<select disabled>
<option value="-1"><?php _e( 'You have no published pages yet.', 'fictioneer' ); ?></option>
</select>
<?php endif; ?>
<p class="description"><?php _e( 'Rendered inside your public author profile. This will override your biographical info.', 'fictioneer' ) ?></p>
</td>
</tr>
<tr class="user-support-message-wrap">
<th><label for="fictioneer_support_message"><?php _e( 'Support Message', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_support_message" type="text" id="fictioneer_support_message" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_support_message', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Rendered at the bottom of your chapters. This will override "You can support the author on".', 'fictioneer' ) ?></p>
</td>
</tr>
<tr class="user-support-links-wrap">
<th><?php _e( 'Support Links', 'fictioneer' ) ?></th>
<td>
<fieldset>
<input name="fictioneer_user_patreon_link" type="text" id="fictioneer_user_patreon_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_patreon_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Patreon link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_kofi_link" type="text" id="fictioneer_user_kofi_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_kofi_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Ko-Fi link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_subscribestar_link" type="text" id="fictioneer_user_subscribestar_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_subscribestar_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'SubscribeStar link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_paypal_link" type="text" id="fictioneer_user_paypal_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_paypal_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'PayPal link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_donation_link" type="text" id="fictioneer_user_donation_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_donation_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Generic donation link', 'fictioneer' ) ?></p>
</fieldset>
</td>
</tr>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<tr class="user-author-page-wrap">
<th><label for="fictioneer_author_page"><?php _e( 'Author Page', 'fictioneer' ) ?></label></th>
<td>
<?php if ( $profile_user_has_pages ) : ?>
<?php
wp_dropdown_pages(
array(
'name' => 'fictioneer_author_page',
'id' => 'fictioneer_author_page',
'option_none_value' => __( 'None', 'fictioneer' ),
'show_option_no_change' => __( 'None', 'fictioneer' ),
'selected' => get_the_author_meta( 'fictioneer_author_page', $profile_user->ID ),
'authors' => $profile_user->ID
)
);
?>
<?php else : ?>
<select disabled>
<option value="-1"><?php _e( 'You have no published pages yet.', 'fictioneer' ); ?></option>
</select>
<?php endif; ?>
<p class="description"><?php _e( 'Rendered inside your public author profile. This will override your biographical info.', 'fictioneer' ) ?></p>
</td>
</tr>
<tr class="user-support-message-wrap">
<th><label for="fictioneer_support_message"><?php _e( 'Support Message', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_support_message" type="text" id="fictioneer_support_message" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_support_message', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Rendered at the bottom of your chapters. This will override "You can support the author on".', 'fictioneer' ) ?></p>
</td>
</tr>
<tr class="user-support-links-wrap">
<th><?php _e( 'Support Links', 'fictioneer' ) ?></th>
<td>
<fieldset>
<input name="fictioneer_user_patreon_link" type="text" id="fictioneer_user_patreon_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_patreon_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Patreon link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_kofi_link" type="text" id="fictioneer_user_kofi_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_kofi_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Ko-Fi link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_subscribestar_link" type="text" id="fictioneer_user_subscribestar_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_subscribestar_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'SubscribeStar link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_paypal_link" type="text" id="fictioneer_user_paypal_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_paypal_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'PayPal link', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_user_donation_link" type="text" id="fictioneer_user_donation_link" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_user_donation_link', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Generic donation link', 'fictioneer' ) ?></p>
</fieldset>
</td>
</tr>
<?php // <--- End HTML
}
add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_author', 20 );
@ -821,35 +817,33 @@ add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_author',
* currently editing the profile!
*/
if ( ! function_exists( 'fictioneer_admin_profile_oauth' ) ) {
function fictioneer_admin_profile_oauth( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
function fictioneer_admin_profile_oauth( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin || ! get_option( 'fictioneer_enable_oauth' ) ) return;
// Abort conditions...
if ( ! $editing_user_is_admin || ! get_option( 'fictioneer_enable_oauth' ) ) return;
// Start HTML ---> ?>
<tr class="user-oauth-connections-wrap">
<th><?php _e( 'Account Bindings', 'fictioneer' ) ?></th>
<td>
<fieldset>
<input name="fictioneer_discord_id_hash" type="text" id="fictioneer_discord_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_discord_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Discord ID Hash', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_twitch_id_hash" type="text" id="fictioneer_twitch_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_twitch_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Twitch ID Hash', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_google_id_hash" type="text" id="fictioneer_google_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_google_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Google ID Hash', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_patreon_id_hash" type="text" id="fictioneer_patreon_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_patreon_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Patreon ID Hash', 'fictioneer' ) ?></p>
</fieldset>
</td>
</tr>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<tr class="user-oauth-connections-wrap">
<th><?php _e( 'Account Bindings', 'fictioneer' ) ?></th>
<td>
<fieldset>
<input name="fictioneer_discord_id_hash" type="text" id="fictioneer_discord_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_discord_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Discord ID Hash', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_twitch_id_hash" type="text" id="fictioneer_twitch_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_twitch_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Twitch ID Hash', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_google_id_hash" type="text" id="fictioneer_google_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_google_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Google ID Hash', 'fictioneer' ) ?></p>
<br>
<input name="fictioneer_patreon_id_hash" type="text" id="fictioneer_patreon_id_hash" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_patreon_id_hash', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Patreon ID Hash', 'fictioneer' ) ?></p>
</fieldset>
</td>
</tr>
<?php // <--- End HTML
}
if ( FICTIONEER_SHOW_OAUTH_HASHES ) {
@ -869,24 +863,22 @@ if ( FICTIONEER_SHOW_OAUTH_HASHES ) {
* currently editing the profile!
*/
if ( ! function_exists( 'fictioneer_admin_profile_badge' ) ) {
function fictioneer_admin_profile_badge( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
function fictioneer_admin_profile_badge( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Start HTML ---> ?>
<tr class="user-badge-override-wrap">
<th><label for="fictioneer_badge_override"><?php _e( 'Badge Override', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_badge_override" type="text" id="fictioneer_badge_override" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_badge_override', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Override the users badge.', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<tr class="user-badge-override-wrap">
<th><label for="fictioneer_badge_override"><?php _e( 'Badge Override', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_badge_override" type="text" id="fictioneer_badge_override" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_badge_override', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'Override the users badge.', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_badge', 40 );
@ -903,96 +895,23 @@ add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_badge',
* currently editing the profile!
*/
if ( ! function_exists( 'fictioneer_admin_profile_external_avatar' ) ) {
function fictioneer_admin_profile_external_avatar( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
function fictioneer_admin_profile_external_avatar( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Start HTML ---> ?>
<tr class="user-external-avatar-wrap">
<th><label for="fictioneer_external_avatar_url"><?php _e( 'External Avatar URL', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_external_avatar_url" type="text" id="fictioneer_external_avatar_url" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_external_avatar_url', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'There is no guarantee this URL remains valid!', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
// Start HTML ---> ?>
<tr class="user-external-avatar-wrap">
<th><label for="fictioneer_external_avatar_url"><?php _e( 'External Avatar URL', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_external_avatar_url" type="text" id="fictioneer_external_avatar_url" value="<?php echo esc_attr( get_the_author_meta( 'fictioneer_external_avatar_url', $profile_user->ID ) ); ?>" class="regular-text">
<p class="description"><?php _e( 'There is no guarantee this URL remains valid!', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_external_avatar', 50 );
// =============================================================================
// SHOW PATREON TIERS
// =============================================================================
/**
* Adds HTML for the Patreon tiers section to the wp-admin user profile
*
* DISABLED!
*
* @since Fictioneer 5.0
*
* @param WP_User $profile_user The profile user object. Not necessarily the one
* currently editing the profile!
*/
if ( ! function_exists( 'fictioneer_admin_profile_patreon_tiers' ) ) {
function fictioneer_admin_profile_patreon_tiers( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Start HTML ---> ?>
<tr class="user-patreon-tiers-wrap">
<th><label for="fictioneer_patreon_tiers"><?php _e( 'Patreon Tiers', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_patreon_tiers" type="text" id="fictioneer_patreon_tiers" value="<?php echo esc_attr( json_encode( get_the_author_meta( 'fictioneer_patreon_tiers', $profile_user->ID ) ) ); ?>" class="regular-text" readonly>
<p class="description"><?php _e( 'Patreon tiers for the linked Patreon client. Valid for two weeks after last login.', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
}
// add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_patreon_tiers', 60 );
// =============================================================================
// SHOW BOOKMARKS SECTION
// =============================================================================
/**
* Adds HTML for the bookmarks section to the wp-admin user profile
*
* DISABLED!
*
* @since Fictioneer 5.0
*
* @param WP_User $profile_user The profile user object. Not necessarily the one
* currently editing the profile!
*/
if ( ! function_exists( 'fictioneer_admin_profile_bookmarks' ) ) {
function fictioneer_admin_profile_bookmarks( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Start HTML ---> ?>
<tr class="user-bookmarks-wrap">
<th><label for="user_bookmarks"><?php _e( 'Bookmarks JSON', 'fictioneer' ) ?></label></th>
<td>
<textarea name="user_bookmarks" id="user_bookmarks" rows="12" cols="30" style="font-family: monospace; font-size: 12px; word-break: break-all;" disabled><?php echo esc_attr( get_the_author_meta( 'fictioneer_bookmarks', $profile_user->ID ) ); ?></textarea>
</td>
</tr>
<?php // <--- End HTML
}
}
// add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_bookmarks', 70 );
?>

View File

@ -4,43 +4,41 @@
// AVATAR FALLBACK
// =============================================================================
if ( ! function_exists( 'fictioneer_avatar_fallback' ) ) {
/**
* Add fallback inline script to avatars
*
* @since Fictioneer 5.0
*
* @param string $avatar HTML for the avatar.
* @param string $id_or_email ID or email of the user.
*
* @return string HTML with fallback script added.
*/
/**
* Add fallback inline script to avatars
*
* @since Fictioneer 5.0
*
* @param string $avatar HTML for the avatar.
* @param string $id_or_email ID or email of the user.
*
* @return string HTML with fallback script added.
*/
function fictioneer_avatar_fallback( $avatar, $id_or_email ) {
$transient = get_transient( 'fictioneer_default_avatar' );
function fictioneer_avatar_fallback( $avatar, $id_or_email ) {
$transient = get_transient( 'fictioneer_default_avatar' );
// Check Transient
if (
empty( $transient ) ||
! is_array( $transient ) ||
$transient['timestamp'] + DAY_IN_SECONDS < time()
) {
$default_url = get_avatar_url( 'nonexistentemail@example.com' );
// Check Transient
if (
empty( $transient ) ||
! is_array( $transient ) ||
$transient['timestamp'] + DAY_IN_SECONDS < time()
) {
$default_url = get_avatar_url( 'nonexistentemail@example.com' );
$transient = array(
'url' => $default_url,
'timestamp' => time()
);
$transient = array(
'url' => $default_url,
'timestamp' => time()
);
set_transient( 'fictioneer_default_avatar', $transient );
} else {
$default_url = $transient['url'];
}
return str_replace( '<img', '<img onerror="this.src=\'' . $default_url . '\';this.srcset=\'\';this.onerror=\'\';"', $avatar );
set_transient( 'fictioneer_default_avatar', $transient );
} else {
$default_url = $transient['url'];
}
return str_replace( '<img', '<img onerror="this.src=\'' . $default_url . '\';this.srcset=\'\';this.onerror=\'\';"', $avatar );
}
add_filter( 'get_avatar' , 'fictioneer_avatar_fallback' , 1 , 2 );
add_filter( 'get_avatar', 'fictioneer_avatar_fallback', 1, 2 );
// =============================================================================
// GET CUSTOM AVATAR URL
@ -75,75 +73,71 @@ if ( ! function_exists( 'fictioneer_get_custom_avatar_url' ) ) {
// GET CUSTOM AVATAR URL
// =============================================================================
if ( ! function_exists( 'fictioneer_get_avatar_url' ) ) {
/**
* Filter the avatar URL
*
* @since Fictioneer 4.0
*
* @param string $url The default URL by WordPress.
* @param int|string $id_or_email User ID or email address.
* @param WP_User $args Additional arguments.
*
* @return string The avatar URL.
*/
/**
* Filter the avatar URL
*
* @since Fictioneer 4.0
*
* @param string $url The default URL by WordPress.
* @param int|string $id_or_email User ID or email address.
* @param WP_User $args Additional arguments.
*
* @return string The avatar URL.
*/
function fictioneer_get_avatar_url( $url, $id_or_email, $args ) {
// Abort conditions...
if ( $args['force_default'] ?? false ) {
return $url;
}
// Setup
$user = fictioneer_get_user_by_id_or_email( $id_or_email );
$custom_avatar = fictioneer_get_custom_avatar_url( $user );
// Check user and permissions
if ( $user ) {
$user_disabled = $user->fictioneer_disable_avatar;
$admin_disabled = $user->fictioneer_admin_disable_avatar;
if ( $user_disabled || $admin_disabled ) {
return false;
}
}
// Return custom avatar if set
if ( ! empty( $custom_avatar ) ) {
return $custom_avatar;
}
// Return default avatar
function fictioneer_get_avatar_url( $url, $id_or_email, $args ) {
// Abort conditions...
if ( $args['force_default'] ?? false ) {
return $url;
};
}
}
// Setup
$user = fictioneer_get_user_by_id_or_email( $id_or_email );
$custom_avatar = fictioneer_get_custom_avatar_url( $user );
// Check user and permissions
if ( $user ) {
$user_disabled = $user->fictioneer_disable_avatar;
$admin_disabled = $user->fictioneer_admin_disable_avatar;
if ( $user_disabled || $admin_disabled ) {
return false;
}
}
// Return custom avatar if set
if ( ! empty( $custom_avatar ) ) {
return $custom_avatar;
}
// Return default avatar
return $url;
};
add_filter( 'get_avatar_url', 'fictioneer_get_avatar_url', 10, 3 );
// =============================================================================
// GET USER AVATAR URL - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_avatar' ) ) {
/**
* Get user avatar URL via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Get user avatar URL via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_get_avatar() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
function fictioneer_ajax_get_avatar() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) {
wp_send_json_error( array( 'error' => __( 'Request did not pass validation.', 'fictioneer' ) ) );
}
// Response
wp_send_json_success( array( 'url' => get_avatar_url( $user->ID ) ) );
if ( ! $user ) {
wp_send_json_error( array( 'error' => __( 'Request did not pass validation.', 'fictioneer' ) ) );
}
// Response
wp_send_json_success( array( 'url' => get_avatar_url( $user->ID ) ) );
}
add_action( 'wp_ajax_fictioneer_ajax_get_avatar', 'fictioneer_ajax_get_avatar' );

View File

@ -4,28 +4,26 @@
// GET BOOKMARKS FOR USERS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_bookmarks' ) ) {
/**
* Get an user's bookmarks via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Get an user's bookmarks via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_get_bookmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_get_bookmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Look for saved bookmarks on user...
$bookmarks = get_user_meta( $user->ID, 'fictioneer_bookmarks', true );
$bookmarks = $bookmarks ? $bookmarks : '{}';
// Look for saved bookmarks on user...
$bookmarks = get_user_meta( $user->ID, 'fictioneer_bookmarks', true );
$bookmarks = $bookmarks ? $bookmarks : '{}';
// Response
if ( $bookmarks ) wp_send_json_success( ['bookmarks' => $bookmarks] );
}
// Response
if ( $bookmarks ) wp_send_json_success( ['bookmarks' => $bookmarks] );
}
if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
@ -36,52 +34,50 @@ if ( get_option( 'fictioneer_enable_bookmarks' ) ) {
// SAVE BOOKMARKS FOR USERS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_save_bookmarks' ) ) {
/**
* Save bookmarks JSON for user via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Save bookmarks JSON for user via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_save_bookmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_save_bookmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
if ( empty( $_POST['bookmarks'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
// Valid?
$bookmarks = sanitize_text_field( $_POST['bookmarks'] );
if ( $bookmarks && fictioneer_is_valid_json( stripslashes( $bookmarks ) ) ) {
// Inspect
$decoded = json_decode( stripslashes( $bookmarks ), true );
if (
! $decoded ||
! isset( $decoded['data'] ) ||
! isset( $decoded['lastLoaded'] ) ||
count( $decoded ) != 2
) {
wp_send_json_error( ['error' => __( 'Invalid JSON.', 'fictioneer' )] );
}
// Update and response
if ( update_user_meta( $user->ID, 'fictioneer_bookmarks', $bookmarks ) ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Bookmarks could not be updated', 'fictioneer' )] );
}
}
// Something went wrong if we end up here...
wp_send_json_error( ['error' => __( 'Not a valid JSON string.', 'fictioneer' )] );
if ( empty( $_POST['bookmarks'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
// Valid?
$bookmarks = sanitize_text_field( $_POST['bookmarks'] );
if ( $bookmarks && fictioneer_is_valid_json( stripslashes( $bookmarks ) ) ) {
// Inspect
$decoded = json_decode( stripslashes( $bookmarks ), true );
if (
! $decoded ||
! isset( $decoded['data'] ) ||
! isset( $decoded['lastLoaded'] ) ||
count( $decoded ) != 2
) {
wp_send_json_error( ['error' => __( 'Invalid JSON.', 'fictioneer' )] );
}
// Update and response
if ( update_user_meta( $user->ID, 'fictioneer_bookmarks', $bookmarks ) ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Bookmarks could not be updated', 'fictioneer' )] );
}
}
// Something went wrong if we end up here...
wp_send_json_error( ['error' => __( 'Not a valid JSON string.', 'fictioneer' )] );
}
if ( get_option( 'fictioneer_enable_bookmarks' ) ) {

View File

@ -102,29 +102,27 @@ if ( ! function_exists( 'fictioneer_count_chapter_checkmarks' ) ) {
// GET CHECKMARKS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_checkmarks' ) ) {
/**
* Sends the user's Checkmarks as JSON via Ajax
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_load_checkmarks()
*/
/**
* Sends the user's Checkmarks as JSON via Ajax
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_load_checkmarks()
*/
function fictioneer_ajax_get_checkmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_get_checkmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Prepare Checkmarks
$checkmarks = fictioneer_load_checkmarks( $user );
$checkmarks['timestamp'] = time() * 1000; // Compatible with Date.now() in JavaScript
// Prepare Checkmarks
$checkmarks = fictioneer_load_checkmarks( $user );
$checkmarks['timestamp'] = time() * 1000; // Compatible with Date.now() in JavaScript
// Response
wp_send_json_success( ['checkmarks' => json_encode( $checkmarks )] );
}
// Response
wp_send_json_success( ['checkmarks' => json_encode( $checkmarks )] );
}
if ( get_option( 'fictioneer_enable_checkmarks' ) ) {
@ -135,69 +133,67 @@ if ( get_option( 'fictioneer_enable_checkmarks' ) ) {
// SET CHECKMARKS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_set_checkmark' ) ) {
/**
* Set Checkmarks for a story via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_validate_id()
* @see fictioneer_get_story_data()
* @see fictioneer_load_checkmarks()
*/
/**
* Set Checkmarks for a story via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_validate_id()
* @see fictioneer_get_story_data()
* @see fictioneer_load_checkmarks()
*/
function fictioneer_ajax_set_checkmark() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_set_checkmark() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
if ( empty( $_POST['story_id'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
if ( empty( $_POST['story_id'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
$story_id = fictioneer_validate_id( $_POST['story_id'], 'fcn_story' );
$story_id = fictioneer_validate_id( $_POST['story_id'], 'fcn_story' );
if ( ! $story_id ) {
wp_send_json_error( ['error' => __( 'Invalid story ID.', 'fictioneer' )] );
}
if ( ! $story_id ) {
wp_send_json_error( ['error' => __( 'Invalid story ID.', 'fictioneer' )] );
}
$story_data = fictioneer_get_story_data( $story_id, false ); // Does not refresh comment count!
$story_data = fictioneer_get_story_data( $story_id, false ); // Does not refresh comment count!
// Prepare update
$update = isset( $_POST['update'] ) ? explode( ' ', sanitize_text_field( $_POST['update'] ) ) : [];
$update_ids = [];
// Prepare update
$update = isset( $_POST['update'] ) ? explode( ' ', sanitize_text_field( $_POST['update'] ) ) : [];
$update_ids = [];
// Check update...
if ( in_array( $story_id, $update ) ) {
// If story ID in update, add all chapters and mark story as read
$update_ids = array_map( function ( $a ) { return absint( $a ); }, $story_data['chapter_ids'] );
$update_ids[] = absint( $story_id );
} else {
// Check if chapter IDs are part of the story
foreach ( $update as $chapter_id ) {
$chapter_id = absint( $chapter_id );
// Check update...
if ( in_array( $story_id, $update ) ) {
// If story ID in update, add all chapters and mark story as read
$update_ids = array_map( function ( $a ) { return absint( $a ); }, $story_data['chapter_ids'] );
$update_ids[] = absint( $story_id );
} else {
// Check if chapter IDs are part of the story
foreach ( $update as $chapter_id ) {
$chapter_id = absint( $chapter_id );
if ( in_array( $chapter_id, $story_data['chapter_ids'] ) ) {
$update_ids[] = $chapter_id;
}
if ( in_array( $chapter_id, $story_data['chapter_ids'] ) ) {
$update_ids[] = $chapter_id;
}
}
}
// Prepare Checkmarks
$checkmarks = fictioneer_load_checkmarks( $user );
$checkmarks['updated'] = time() * 1000; // Compatible with Date.now() in JavaScript
// Prepare Checkmarks
$checkmarks = fictioneer_load_checkmarks( $user );
$checkmarks['updated'] = time() * 1000; // Compatible with Date.now() in JavaScript
// Update checkmarks
$checkmarks['data'][ $story_id ] = empty( $_POST['update'] ) ? [] : $update_ids;
// Update checkmarks
$checkmarks['data'][ $story_id ] = empty( $_POST['update'] ) ? [] : $update_ids;
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_checkmarks', $checkmarks ) ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Checkmarks could not be updated.', 'fictioneer' )] );
}
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_checkmarks', $checkmarks ) ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Checkmarks could not be updated.', 'fictioneer' )] );
}
}
@ -209,27 +205,25 @@ if ( get_option( 'fictioneer_enable_checkmarks' ) ) {
// CLEAR MY CHECKMARKS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_clear_my_checkmarks' ) ) {
/**
* Clears Checkmarks for a story via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Clears Checkmarks for a story via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_clear_my_checkmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_checkmarks' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_clear_my_checkmarks() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_checkmarks' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_checkmarks', [] ) ) {
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Checkmarks could not be updated.', 'fictioneer' )] );
}
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_checkmarks', [] ) ) {
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Checkmarks could not be updated.', 'fictioneer' )] );
}
}
@ -241,83 +235,81 @@ if ( get_option( 'fictioneer_enable_checkmarks' ) ) {
// GET FINISHED LIST - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_finished_list' ) ) {
function fictioneer_ajax_get_finished_list() {
// Validations
$user = wp_get_current_user();
function fictioneer_ajax_get_finished_list() {
// Validations
$user = wp_get_current_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Not logged in.', 'fictioneer' )] );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Not logged in.', 'fictioneer' )] );
if ( ! check_ajax_referer( 'fictioneer_nonce', 'nonce', false ) ) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Setup
$checkmarks = fictioneer_load_checkmarks( $user );
$post_ids = fictioneer_get_finished_checkmarks( $checkmarks );
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$order = isset( $_GET['order'] ) ? strtolower( $_GET['order'] ) : 'desc';
// Sanitize
$order = in_array( $order, ['desc', 'asc'] ) ? $order : 'desc';
// Query
$list_items = fictioneer_get_card_list(
'story',
array(
'post__in' => $post_ids,
'paged' => $page,
'order' => $order
),
__( 'You have not marked any stories as finished.', 'fictioneer' ),
['show_latest' => true]
);
// Total number of pages
$max_pages = $list_items['query']->max_num_pages ?? 1;
// Navigation (if any)
$navigation = '';
if ( $max_pages > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<?php
for ( $i = 1; $i <= $max_pages; $i++ ) {
if ( $i == $page ) {
?><span class="page-numbers current" aria-current="page"><?php echo $i; ?></span><?php
} else {
?><button class="page-numbers" data-page="<?php echo $i; ?>"><?php echo $i; ?></button><?php
}
}
?>
</li>
<?php // <--- End HTML
// Get buffered navigation
$navigation = ob_get_clean();
} elseif ( $page > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<button class="page-numbers" data-page="1"><?php _e( 'First Page', 'fictioneer' ); ?></button>
</li>
<?php // <--- End HTML
// Get buffered back button
$navigation = ob_get_clean();
}
// Send result
wp_send_json_success(
array(
'html' => $list_items['html'] . $navigation,
'count' => count( $post_ids ),
'maxPages' => $max_pages
)
);
if ( ! check_ajax_referer( 'fictioneer_nonce', 'nonce', false ) ) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Setup
$checkmarks = fictioneer_load_checkmarks( $user );
$post_ids = fictioneer_get_finished_checkmarks( $checkmarks );
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$order = isset( $_GET['order'] ) ? strtolower( $_GET['order'] ) : 'desc';
// Sanitize
$order = in_array( $order, ['desc', 'asc'] ) ? $order : 'desc';
// Query
$list_items = fictioneer_get_card_list(
'story',
array(
'post__in' => $post_ids,
'paged' => $page,
'order' => $order
),
__( 'You have not marked any stories as finished.', 'fictioneer' ),
['show_latest' => true]
);
// Total number of pages
$max_pages = $list_items['query']->max_num_pages ?? 1;
// Navigation (if any)
$navigation = '';
if ( $max_pages > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<?php
for ( $i = 1; $i <= $max_pages; $i++ ) {
if ( $i == $page ) {
?><span class="page-numbers current" aria-current="page"><?php echo $i; ?></span><?php
} else {
?><button class="page-numbers" data-page="<?php echo $i; ?>"><?php echo $i; ?></button><?php
}
}
?>
</li>
<?php // <--- End HTML
// Get buffered navigation
$navigation = ob_get_clean();
} elseif ( $page > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<button class="page-numbers" data-page="1"><?php _e( 'First Page', 'fictioneer' ); ?></button>
</li>
<?php // <--- End HTML
// Get buffered back button
$navigation = ob_get_clean();
}
// Send result
wp_send_json_success(
array(
'html' => $list_items['html'] . $navigation,
'count' => count( $post_ids ),
'maxPages' => $max_pages
)
);
}
if ( get_option( 'fictioneer_enable_checkmarks' ) ) {

View File

@ -48,42 +48,40 @@ if ( ! function_exists( 'fictioneer_load_follows' ) ) {
// GET FOLLOWS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_follows' ) ) {
/**
* Sends the user's Follows as JSON via Ajax
*
* @since Fictioneer 4.3
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Sends the user's Follows as JSON via Ajax
*
* @since Fictioneer 4.3
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_get_follows() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_get_follows() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Prepare Follows
$user_follows = fictioneer_load_follows( $user );
$user_follows['timestamp'] = time() * 1000; // Compatible with Date.now() in JavaScript
$latest = 0;
$new = false;
// Prepare Follows
$user_follows = fictioneer_load_follows( $user );
$user_follows['timestamp'] = time() * 1000; // Compatible with Date.now() in JavaScript
$latest = 0;
$new = false;
// New notifications?
if ( count( $user_follows['data'] ) > 0 ) {
$latest = fictioneer_query_followed_chapters(
array_keys( $user_follows['data'] ),
wp_date( 'c', $user_follows['seen'] / 1000 )
);
// New notifications?
if ( count( $user_follows['data'] ) > 0 ) {
$latest = fictioneer_query_followed_chapters(
array_keys( $user_follows['data'] ),
wp_date( 'c', $user_follows['seen'] / 1000 )
);
if ( $latest ) $new = count( $latest );
}
$user_follows['new'] = $new;
// Response
wp_send_json_success( ['follows' => json_encode( $user_follows )] );
if ( $latest ) $new = count( $latest );
}
$user_follows['new'] = $new;
// Response
wp_send_json_success( ['follows' => json_encode( $user_follows )] );
}
if ( get_option( 'fictioneer_enable_follows' ) ) {
@ -94,61 +92,59 @@ if ( get_option( 'fictioneer_enable_follows' ) ) {
// TOGGLE FOLLOW - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_toggle_follow' ) ) {
/**
* Toggle Follow for a story via AJAX
*
* @since Fictioneer 4.3
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_load_follows()
*/
/**
* Toggle Follow for a story via AJAX
*
* @since Fictioneer 4.3
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_load_follows()
*/
function fictioneer_ajax_toggle_follow() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_toggle_follow() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
if ( empty( $_POST['story_id'] ) || empty( $_POST['set'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
if ( empty( $_POST['story_id'] ) || empty( $_POST['set'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
// Valid story ID?
$story_id = fictioneer_validate_id( $_POST['story_id'], 'fcn_story' );
if ( ! $story_id ) {
wp_send_json_error( ['error' => __( 'Invalid story ID.', 'fictioneer' )] );
}
// Valid story ID?
$story_id = fictioneer_validate_id( $_POST['story_id'], 'fcn_story' );
if ( ! $story_id ) {
wp_send_json_error( ['error' => __( 'Invalid story ID.', 'fictioneer' )] );
}
// Set or unset?
$set = $_POST['set'] == 'true';
// Set or unset?
$set = $_POST['set'] == 'true';
// Prepare Follows
$timestamp = time() * 1000; // Compatible with Date.now() in JavaScript
$user_follows = fictioneer_load_follows( $user );
$user_follows['updated'] = $timestamp;
// Prepare Follows
$timestamp = time() * 1000; // Compatible with Date.now() in JavaScript
$user_follows = fictioneer_load_follows( $user );
$user_follows['updated'] = $timestamp;
// Add/Remove story from Follows
if ( ! array_key_exists( $story_id, $user_follows['data'] ) || $set ) {
$item = array(
'user_id' => $user->ID,
'story_id' => $story_id,
'timestamp' => $timestamp
);
// Add/Remove story from Follows
if ( ! array_key_exists( $story_id, $user_follows['data'] ) || $set ) {
$item = array(
'user_id' => $user->ID,
'story_id' => $story_id,
'timestamp' => $timestamp
);
$user_follows['data'][ $story_id ] = $item;
} else {
unset( $user_follows['data'][ $story_id ] );
}
$user_follows['data'][ $story_id ] = $item;
} else {
unset( $user_follows['data'][ $story_id ] );
}
// Update database & response
delete_user_meta( $user->ID, 'fictioneer_user_follows_cache' );
// Update database & response
delete_user_meta( $user->ID, 'fictioneer_user_follows_cache' );
if ( update_user_meta( $user->ID, 'fictioneer_user_follows', $user_follows ) ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Follows could not be updated.', 'fictioneer' )] );
}
if ( update_user_meta( $user->ID, 'fictioneer_user_follows', $user_follows ) ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Follows could not be updated.', 'fictioneer' )] );
}
}
@ -160,28 +156,26 @@ if ( get_option( 'fictioneer_enable_follows' ) ) {
// CLEAR MY FOLLOWS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_clear_my_follows' ) ) {
/**
* Clears an user's Follows via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Clears an user's Follows via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_clear_my_follows() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_follows' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_clear_my_follows() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_follows' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_follows', [] ) ) {
update_user_meta( $user->ID, 'fictioneer_user_follows_cache', false );
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Follows could not be cleared.', 'fictioneer' )] );
}
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_follows', [] ) ) {
update_user_meta( $user->ID, 'fictioneer_user_follows_cache', false );
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Follows could not be cleared.', 'fictioneer' )] );
}
}
@ -193,44 +187,42 @@ if ( get_option( 'fictioneer_enable_follows' ) ) {
// MARK FOLLOWS AS READ - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_mark_follows_read' ) ) {
/**
* Mark all Follows as read via AJAX
*
* Updates the 'seen' timestamp in the 'fictioneer_user_follows' meta data,
* which is used to determine whether Follows are new. This will mark all
* of them as read, you cannot mark single items in the list as read.
*
* @since Fictioneer 4.3
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Mark all Follows as read via AJAX
*
* Updates the 'seen' timestamp in the 'fictioneer_user_follows' meta data,
* which is used to determine whether Follows are new. This will mark all
* of them as read, you cannot mark single items in the list as read.
*
* @since Fictioneer 4.3
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_mark_follows_read() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_mark_follows_read() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
$user_follows = fictioneer_load_follows( $user );
$user_follows = fictioneer_load_follows( $user );
if ( empty( $user_follows ) ) {
wp_send_json_error( ['error' => __( 'Follows are empty.', 'fictioneer' )] );
}
if ( empty( $user_follows ) ) {
wp_send_json_error( ['error' => __( 'Follows are empty.', 'fictioneer' )] );
}
// Update 'seen' timestamp to now; compatible with Date.now() in JavaScript
$user_follows['seen'] = time() * 1000;
// Update 'seen' timestamp to now; compatible with Date.now() in JavaScript
$user_follows['seen'] = time() * 1000;
// Update database
update_user_meta( $user->ID, 'fictioneer_user_follows_cache', false );
$result = update_user_meta( $user->ID, 'fictioneer_user_follows', $user_follows );
// Update database
update_user_meta( $user->ID, 'fictioneer_user_follows_cache', false );
$result = update_user_meta( $user->ID, 'fictioneer_user_follows', $user_follows );
// Response
if ( $result ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Follows could not be updated.', 'fictioneer' )] );
}
// Response
if ( $result ) {
wp_send_json_success();
} else {
wp_send_json_error( ['error' => __( 'Database error. Follows could not be updated.', 'fictioneer' )] );
}
}
@ -297,97 +289,95 @@ if ( ! function_exists( 'fictioneer_query_followed_chapters' ) ) {
// GET FOLLOWS NOTIFICATIONS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_follows_notifications' ) ) {
/**
* Sends the HTML for Follows notifications via AJAX
*
* @since Fictioneer 4.3
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Sends the HTML for Follows notifications via AJAX
*
* @since Fictioneer 4.3
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_get_follows_notifications() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error(
array(
'error' => __( 'Not logged in.', 'fictioneer' ),
'html' => '<div class="follow-item"><div class="follow-wrapper"><div class="follow-placeholder truncate _1-1">' . __( 'Not logged in.', 'fictioneer' ) . '</div></div></div>'
)
);
function fictioneer_ajax_get_follows_notifications() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error(
array(
'error' => __( 'Not logged in.', 'fictioneer' ),
'html' => '<div class="follow-item"><div class="follow-wrapper"><div class="follow-placeholder truncate _1-1">' . __( 'Not logged in.', 'fictioneer' ) . '</div></div></div>'
)
);
// Follows
$user_follows = fictioneer_load_follows( $user );
// Follows
$user_follows = fictioneer_load_follows( $user );
// Last story/chapter update on site
$last_update = fictioneer_get_last_fiction_update();
// Last story/chapter update on site
$last_update = fictioneer_get_last_fiction_update();
// Check for cached HTML
if ( ! empty( $last_update ) ) {
$cache = get_user_meta( $user->ID, 'fictioneer_user_follows_cache', true );
if ( ! empty( $cache ) && array_key_exists( $last_update, $cache ) ) {
$html = $cache[ $last_update ] . '<!-- Cached on ' . $cache['timestamp'] . ' -->';
wp_send_json_success( ['html' => $html] );
}
// Check for cached HTML
if ( ! empty( $last_update ) ) {
$cache = get_user_meta( $user->ID, 'fictioneer_user_follows_cache', true );
if ( ! empty( $cache ) && array_key_exists( $last_update, $cache ) ) {
$html = $cache[ $last_update ] . '<!-- Cached on ' . $cache['timestamp'] . ' -->';
wp_send_json_success( ['html' => $html] );
}
}
// Chapters for notifications
$chapters = count( $user_follows['data'] ) > 0 ? fictioneer_query_followed_chapters( array_keys( $user_follows['data'] ) ) : false;
// Chapters for notifications
$chapters = count( $user_follows['data'] ) > 0 ? fictioneer_query_followed_chapters( array_keys( $user_follows['data'] ) ) : false;
// Build notifications
ob_start();
// Build notifications
ob_start();
if ( $chapters ) {
foreach ( $chapters as $chapter ) {
$date = get_the_date(
sprintf(
_x( '%1$s \a\t %2$s', 'Date in Follows update list.', 'fictioneer' ),
get_option('date_format'),
get_option('time_format')
), $chapter->ID
);
$chapter_timestamp = get_post_timestamp( $chapter->ID ) * 1000; // Compatible with Date.now() in JavaScript
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $chapter->ID );
$new = $user_follows['seen'] < $chapter_timestamp ? '_new' : '';
if ( $chapters ) {
foreach ( $chapters as $chapter ) {
$date = get_the_date(
sprintf(
_x( '%1$s \a\t %2$s', 'Date in Follows update list.', 'fictioneer' ),
get_option('date_format'),
get_option('time_format')
), $chapter->ID
);
$chapter_timestamp = get_post_timestamp( $chapter->ID ) * 1000; // Compatible with Date.now() in JavaScript
$story_id = fictioneer_get_field( 'fictioneer_chapter_story', $chapter->ID );
$new = $user_follows['seen'] < $chapter_timestamp ? '_new' : '';
// Start HTML ---> ?>
<div class="follow-item <?php echo $new; ?>" data-chapter-id="<?php echo $chapter->ID; ?>" data-story-id="<?php echo $story_id; ?>" data-timestamp="<?php echo $chapter_timestamp; ?>">
<div class="follow-wrapper">
<div class="follow-title truncate _1-1">
<a href="<?php echo get_the_permalink( $chapter->ID ); ?>"><?php echo fictioneer_get_safe_title( $chapter->ID ); ?></a>
</div>
<div class="follow-meta truncate _1-1"><?php echo $date ; ?> in <?php echo fictioneer_get_safe_title( $story_id ); ?></div>
<div class="follow-marker">&bull;</div>
</div>
</div>
<?php // <--- End HTML
}
} else {
// Start HTML ---> ?>
<div class="follow-item">
<div class="follow-item <?php echo $new; ?>" data-chapter-id="<?php echo $chapter->ID; ?>" data-story-id="<?php echo $story_id; ?>" data-timestamp="<?php echo $chapter_timestamp; ?>">
<div class="follow-wrapper">
<div class="follow-placeholder truncate _1-1"><?php _e( 'You are not following any stories.', 'fictioneer' ); ?></div>
<div class="follow-title truncate _1-1">
<a href="<?php echo get_the_permalink( $chapter->ID ); ?>"><?php echo fictioneer_get_safe_title( $chapter->ID ); ?></a>
</div>
<div class="follow-meta truncate _1-1"><?php echo $date ; ?> in <?php echo fictioneer_get_safe_title( $story_id ); ?></div>
<div class="follow-marker">&bull;</div>
</div>
</div>
<?php // <--- End HTML
}
$html = fictioneer_minify_html( ob_get_clean() );
// Cache for next time
if ( ! empty( $last_update ) ) {
update_user_meta(
$user->ID,
'fictioneer_user_follows_cache',
array(
$last_update => $html,
'timestamp' => time() * 1000
)
);
}
// Return HTML
wp_send_json_success( array( 'html' => $html ) );
} else {
// Start HTML ---> ?>
<div class="follow-item">
<div class="follow-wrapper">
<div class="follow-placeholder truncate _1-1"><?php _e( 'You are not following any stories.', 'fictioneer' ); ?></div>
</div>
</div>
<?php // <--- End HTML
}
$html = fictioneer_minify_html( ob_get_clean() );
// Cache for next time
if ( ! empty( $last_update ) ) {
update_user_meta(
$user->ID,
'fictioneer_user_follows_cache',
array(
$last_update => $html,
'timestamp' => time() * 1000
)
);
}
// Return HTML
wp_send_json_success( array( 'html' => $html ) );
}
if ( get_option( 'fictioneer_enable_follows' ) ) {
@ -398,91 +388,89 @@ if ( get_option( 'fictioneer_enable_follows' ) ) {
// GET FOLLOWS LIST - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_follows_list' ) ) {
/**
* Sends the HTML for Follows list via AJAX
*
* @since Fictioneer 4.3
*/
/**
* Sends the HTML for Follows list via AJAX
*
* @since Fictioneer 4.3
*/
function fictioneer_ajax_get_follows_list() {
// Validations
$user = wp_get_current_user();
function fictioneer_ajax_get_follows_list() {
// Validations
$user = wp_get_current_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Not logged in.', 'fictioneer' )] );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Not logged in.', 'fictioneer' )] );
if ( ! check_ajax_referer( 'fictioneer_nonce', 'nonce', false ) ) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Setup
$follows = fictioneer_load_follows( $user );
$post_ids = array_keys( $follows['data'] );
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$order = isset( $_GET['order'] ) ? strtolower( $_GET['order'] ) : 'desc';
// Sanitize
$order = in_array( $order, ['desc', 'asc'] ) ? $order : 'desc';
// Query
$list_items = fictioneer_get_card_list(
'story',
array(
'post__in' => $post_ids,
'paged' => $page,
'order' => $order
),
__( 'You are not following any stories.', 'fictioneer' ),
array(
'show_latest' => true
)
);
// Total number of pages
$max_pages = $list_items['query']->max_num_pages ?? 1;
// Navigation (if any)
$navigation = '';
if ( $max_pages > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<?php
for ( $i = 1; $i <= $max_pages; $i++ ) {
if ( $i == $page ) {
?><span class="page-numbers current" aria-current="page"><?php echo $i; ?></span><?php
} else {
?><button class="page-numbers" data-page="<?php echo $i; ?>"><?php echo $i; ?></button><?php
}
}
?>
</li>
<?php // <--- End HTML
// Get buffered navigation
$navigation = ob_get_clean();
} elseif ( $page > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<button class="page-numbers" data-page="1"><?php _e( 'First Page', 'fictioneer' ); ?></button>
</li>
<?php // <--- End HTML
// Get buffered back button
$navigation = ob_get_clean();
}
// Send result
wp_send_json_success(
array(
'html' => fictioneer_minify_html( $list_items['html'] ) . $navigation,
'count' => count( $post_ids ),
'maxPages' => $max_pages
)
);
if ( ! check_ajax_referer( 'fictioneer_nonce', 'nonce', false ) ) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Setup
$follows = fictioneer_load_follows( $user );
$post_ids = array_keys( $follows['data'] );
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$order = isset( $_GET['order'] ) ? strtolower( $_GET['order'] ) : 'desc';
// Sanitize
$order = in_array( $order, ['desc', 'asc'] ) ? $order : 'desc';
// Query
$list_items = fictioneer_get_card_list(
'story',
array(
'post__in' => $post_ids,
'paged' => $page,
'order' => $order
),
__( 'You are not following any stories.', 'fictioneer' ),
array(
'show_latest' => true
)
);
// Total number of pages
$max_pages = $list_items['query']->max_num_pages ?? 1;
// Navigation (if any)
$navigation = '';
if ( $max_pages > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<?php
for ( $i = 1; $i <= $max_pages; $i++ ) {
if ( $i == $page ) {
?><span class="page-numbers current" aria-current="page"><?php echo $i; ?></span><?php
} else {
?><button class="page-numbers" data-page="<?php echo $i; ?>"><?php echo $i; ?></button><?php
}
}
?>
</li>
<?php // <--- End HTML
// Get buffered navigation
$navigation = ob_get_clean();
} elseif ( $page > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<button class="page-numbers" data-page="1"><?php _e( 'First Page', 'fictioneer' ); ?></button>
</li>
<?php // <--- End HTML
// Get buffered back button
$navigation = ob_get_clean();
}
// Send result
wp_send_json_success(
array(
'html' => fictioneer_minify_html( $list_items['html'] ) . $navigation,
'count' => count( $post_ids ),
'maxPages' => $max_pages
)
);
}
if ( get_option( 'fictioneer_enable_follows' ) ) {

View File

@ -43,29 +43,27 @@ if ( ! function_exists( 'fictioneer_load_reminders' ) ) {
// GET REMINDERS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_reminders' ) ) {
/**
* Sends the user's Reminders as JSON via Ajax
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_load_reminders()
*/
/**
* Sends the user's Reminders as JSON via Ajax
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
* @see fictioneer_load_reminders()
*/
function fictioneer_ajax_get_reminders() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_get_reminders() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Prepare Reminders
$reminders = fictioneer_load_reminders( $user );
$reminders['timestamp'] = time() * 1000; // Compatible with Date.now() in JavaScript
// Prepare Reminders
$reminders = fictioneer_load_reminders( $user );
$reminders['timestamp'] = time() * 1000; // Compatible with Date.now() in JavaScript
// Response
wp_send_json_success( ['reminders' => json_encode( $reminders )] );
}
// Response
wp_send_json_success( ['reminders' => json_encode( $reminders )] );
}
if ( get_option( 'fictioneer_enable_reminders' ) ) {
@ -76,57 +74,55 @@ if ( get_option( 'fictioneer_enable_reminders' ) ) {
// TOGGLE REMINDER - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_toggle_reminder' ) ) {
/**
* Set Reminder for a story via AJAX
*
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Set Reminder for a story via AJAX
*
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_toggle_reminder() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_toggle_reminder() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
if ( empty( $_POST['story_id'] ) || empty( $_POST['set'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
if ( empty( $_POST['story_id'] ) || empty( $_POST['set'] ) ) {
wp_send_json_error( ['error' => __( 'Missing arguments.', 'fictioneer' )] );
}
// Valid story ID?
$story_id = fictioneer_validate_id( $_POST['story_id'], 'fcn_story' );
if ( ! $story_id ) wp_send_json_error( ['error' => __( 'Invalid story ID.', 'fictioneer' )] );
// Valid story ID?
$story_id = fictioneer_validate_id( $_POST['story_id'], 'fcn_story' );
if ( ! $story_id ) wp_send_json_error( ['error' => __( 'Invalid story ID.', 'fictioneer' )] );
// Set or unset?
$set = $_POST['set'] == 'true';
// Set or unset?
$set = $_POST['set'] == 'true';
// Prepare Reminders
$timestamp = time() * 1000; // Compatible with Date.now() in JavaScript
$user_reminders = fictioneer_load_reminders( $user );
$user_reminders['updated'] = $timestamp;
// Prepare Reminders
$timestamp = time() * 1000; // Compatible with Date.now() in JavaScript
$user_reminders = fictioneer_load_reminders( $user );
$user_reminders['updated'] = $timestamp;
// Add/Remove story from Reminders
if ( ! array_key_exists( $story_id, $user_reminders['data'] ) || $set ) {
$item = array(
'user_id' => $user->ID,
'story_id' => $story_id,
'timestamp' => $timestamp
);
// Add/Remove story from Reminders
if ( ! array_key_exists( $story_id, $user_reminders['data'] ) || $set ) {
$item = array(
'user_id' => $user->ID,
'story_id' => $story_id,
'timestamp' => $timestamp
);
$user_reminders['data'][ $story_id ] = $item;
} else {
unset( $user_reminders['data'][ $story_id ] );
}
$user_reminders['data'][ $story_id ] = $item;
} else {
unset( $user_reminders['data'][ $story_id ] );
}
// Update database & response
if ( update_user_meta( $user->ID, 'fictioneer_user_reminders', $user_reminders ) ) {
wp_send_json_success();
} {
wp_send_json_error( ['error' => __( 'Database error. Reminders could not be updated.', 'fictioneer' )] );
}
// Update database & response
if ( update_user_meta( $user->ID, 'fictioneer_user_reminders', $user_reminders ) ) {
wp_send_json_success();
} {
wp_send_json_error( ['error' => __( 'Database error. Reminders could not be updated.', 'fictioneer' )] );
}
}
@ -138,27 +134,25 @@ if ( get_option( 'fictioneer_enable_reminders' ) ) {
// CLEAR MY REMINDERS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_clear_my_reminders' ) ) {
/**
* Clears an user's Reminders via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Clears an user's Reminders via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_clear_my_reminders() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_reminders' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_clear_my_reminders() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_reminders' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_reminders', [] ) ) {
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Reminders could not be cleared.', 'fictioneer' )] );
}
// Update user
if ( update_user_meta( $user->ID, 'fictioneer_user_reminders', [] ) ) {
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Reminders could not be cleared.', 'fictioneer' )] );
}
}
@ -170,83 +164,81 @@ if ( get_option( 'fictioneer_enable_reminders' ) ) {
// GET FOLLOWS LIST - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_reminders_list' ) ) {
function fictioneer_ajax_get_reminders_list() {
// Validations
$user = wp_get_current_user();
function fictioneer_ajax_get_reminders_list() {
// Validations
$user = wp_get_current_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Not logged in.', 'fictioneer' )] );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Not logged in.', 'fictioneer' )] );
if ( ! check_ajax_referer( 'fictioneer_nonce', 'nonce', false ) ) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Setup
$reminders = fictioneer_load_reminders( $user );
$post_ids = array_keys( $reminders['data'] );
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$order = isset( $_GET['order'] ) ? strtolower( $_GET['order'] ) : 'desc';
// Sanitize
$order = in_array( $order, ['desc', 'asc'] ) ? $order : 'desc';
// Query
$list_items = fictioneer_get_card_list(
'story',
array(
'post__in' => $post_ids,
'paged' => $page,
'order' => $order
),
__( 'You have not marked any stories to be read later.', 'fictioneer' ),
['show_latest' => true]
);
// Total number of pages
$max_pages = $list_items['query']->max_num_pages ?? 1;
// Navigation (if any)
$navigation = '';
if ( $max_pages > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<?php
for ( $i = 1; $i <= $max_pages; $i++ ) {
if ( $i == $page ) {
?><span class="page-numbers current" aria-current="page"><?php echo $i; ?></span><?php
} else {
?><button class="page-numbers" data-page="<?php echo $i; ?>"><?php echo $i; ?></button><?php
}
}
?>
</li>
<?php // <--- End HTML
// Get buffered navigation
$navigation = ob_get_clean();
} elseif ( $page > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<button class="page-numbers" data-page="1"><?php _e( 'First Page', 'fictioneer' ); ?></button>
</li>
<?php // <--- End HTML
// Get buffered back button
$navigation = ob_get_clean();
}
// Send result
wp_send_json_success(
array(
'html' => $list_items['html'] . $navigation,
'count' => count( $post_ids ),
'maxPages' => $max_pages
)
);
if ( ! check_ajax_referer( 'fictioneer_nonce', 'nonce', false ) ) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Setup
$reminders = fictioneer_load_reminders( $user );
$post_ids = array_keys( $reminders['data'] );
$page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1;
$order = isset( $_GET['order'] ) ? strtolower( $_GET['order'] ) : 'desc';
// Sanitize
$order = in_array( $order, ['desc', 'asc'] ) ? $order : 'desc';
// Query
$list_items = fictioneer_get_card_list(
'story',
array(
'post__in' => $post_ids,
'paged' => $page,
'order' => $order
),
__( 'You have not marked any stories to be read later.', 'fictioneer' ),
['show_latest' => true]
);
// Total number of pages
$max_pages = $list_items['query']->max_num_pages ?? 1;
// Navigation (if any)
$navigation = '';
if ( $max_pages > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<?php
for ( $i = 1; $i <= $max_pages; $i++ ) {
if ( $i == $page ) {
?><span class="page-numbers current" aria-current="page"><?php echo $i; ?></span><?php
} else {
?><button class="page-numbers" data-page="<?php echo $i; ?>"><?php echo $i; ?></button><?php
}
}
?>
</li>
<?php // <--- End HTML
// Get buffered navigation
$navigation = ob_get_clean();
} elseif ( $page > 1 ) {
ob_start();
// Start HTML ---> ?>
<li class="pagination bookshelf-pagination">
<button class="page-numbers" data-page="1"><?php _e( 'First Page', 'fictioneer' ); ?></button>
</li>
<?php // <--- End HTML
// Get buffered back button
$navigation = ob_get_clean();
}
// Send result
wp_send_json_success(
array(
'html' => $list_items['html'] . $navigation,
'count' => count( $post_ids ),
'maxPages' => $max_pages
)
);
}
if ( get_option( 'fictioneer_enable_reminders' ) ) {

View File

@ -519,7 +519,7 @@ if ( ! function_exists( 'fictioneer_get_user_fingerprint' ) ) {
* @param int $user_id User ID to get the hash for.
*
* @return string The unique fingerprint hash or empty string if not found.
*/
*/
function fictioneer_get_user_fingerprint( $user_id ) {
// Setup
@ -547,48 +547,46 @@ if ( ! function_exists( 'fictioneer_get_user_fingerprint' ) ) {
// SELF-UNSET OAUTH CONNECTIONS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_unset_my_oauth' ) ) {
/**
* Unset one of the user's OAuth bindings via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
*/
/**
* Unset one of the user's OAuth bindings via AJAX
*
* @since Fictioneer 4.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
*/
function fictioneer_ajax_unset_my_oauth() {
// Setup
$sender_id = isset( $_POST['id'] ) ? fictioneer_validate_id( $_POST['id'] ) : false;
$channel = isset( $_POST['channel'] ) ? sanitize_text_field( $_POST['channel'] ) : false;
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_unset_oauth' );
function fictioneer_ajax_unset_my_oauth() {
// Setup
$sender_id = isset( $_POST['id'] ) ? fictioneer_validate_id( $_POST['id'] ) : false;
$channel = isset( $_POST['channel'] ) ? sanitize_text_field( $_POST['channel'] ) : false;
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_unset_oauth' );
// Validations
if (
! $user ||
! $sender_id ||
! $channel ||
! in_array( $channel, ['discord', 'twitch', 'patreon', 'google'] ) ||
$sender_id !== $user->ID
) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Validations
if (
! $user ||
! $sender_id ||
! $channel ||
! in_array( $channel, ['discord', 'twitch', 'patreon', 'google'] ) ||
$sender_id !== $user->ID
) {
wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
}
// Delete connection
if ( delete_user_meta( $user->ID, "fictioneer_{$channel}_id_hash" ) ) {
// Success response
wp_send_json_success(
array(
'channel' => $channel,
'label' => sprintf(
__( '%s disconnected', 'fictioneer' ),
ucfirst( $channel )
)
// Delete connection
if ( delete_user_meta( $user->ID, "fictioneer_{$channel}_id_hash" ) ) {
// Success response
wp_send_json_success(
array(
'channel' => $channel,
'label' => sprintf(
__( '%s disconnected', 'fictioneer' ),
ucfirst( $channel )
)
);
} else {
// Failure response
wp_send_json_error( ['error' => __( 'Database error. Please ask an administrator.', 'fictioneer' )] );
}
)
);
} else {
// Failure response
wp_send_json_error( ['error' => __( 'Database error. Please ask an administrator.', 'fictioneer' )] );
}
}
add_action( 'wp_ajax_fictioneer_ajax_unset_my_oauth', 'fictioneer_ajax_unset_my_oauth' );
@ -613,7 +611,7 @@ if ( ! function_exists( 'fictioneer_soft_delete_user_comments' ) ) {
* for completeness, partial success, and errors. Includes
* 'complete' (boolean), 'failure' (boolean), 'success' (boolean),
* 'comment_count' (int), and 'updated_count' (int). Or false.
*/
*/
function fictioneer_soft_delete_user_comments( $user_id ) {
// Setup
@ -673,65 +671,63 @@ if ( ! function_exists( 'fictioneer_soft_delete_user_comments' ) ) {
// SELF-CLEAR USER COMMENTS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_clear_my_comments' ) ) {
/**
* Clears all the user's comments via AJAX
*
* Queries all comments of the user and overrides the comment data with
* garbage, preserving the comment thread integrity.
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Clears all the user's comments via AJAX
*
* Queries all comments of the user and overrides the comment data with
* garbage, preserving the comment thread integrity.
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_clear_my_comments() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_comments' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_clear_my_comments() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_comments' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
if (
fictioneer_is_admin( $user->ID ) ||
fictioneer_is_author( $user->ID ) ||
fictioneer_is_moderator( $user->ID ) )
{
wp_send_json_error( ['error' => __( 'User role too high. Please ask an administrator.', 'fictioneer' )] );
}
if (
fictioneer_is_admin( $user->ID ) ||
fictioneer_is_author( $user->ID ) ||
fictioneer_is_moderator( $user->ID ) )
{
wp_send_json_error( ['error' => __( 'User role too high. Please ask an administrator.', 'fictioneer' )] );
}
// Soft-delete comments
$result = fictioneer_soft_delete_user_comments( $user->ID );
// Soft-delete comments
$result = fictioneer_soft_delete_user_comments( $user->ID );
if ( ! $result ) {
wp_send_json_error( ['error' => __( 'Database error. No comments found.', 'fictioneer' )] );
}
if ( ! $result ) {
wp_send_json_error( ['error' => __( 'Database error. No comments found.', 'fictioneer' )] );
}
if ( $result['failure'] && ! $result['complete'] ) {
wp_send_json_error(
array(
'error' => sprintf(
__( 'Partial database error. Only %1$s of %2$s comments could be cleared.', 'fictioneer' ),
$result['updated_count'],
$result['comment_count']
)
)
);
}
if ( $result['failure'] ) {
wp_send_json_error( ['error' => __( 'Database error. Comments could not be cleared.', 'fictioneer' )] );
}
// Report success
wp_send_json_success(
if ( $result['failure'] && ! $result['complete'] ) {
wp_send_json_error(
array(
'success' => sprintf(
__( '%s comments have been cleared.', 'fictioneer' ),
$result['updated_count']
'error' => sprintf(
__( 'Partial database error. Only %1$s of %2$s comments could be cleared.', 'fictioneer' ),
$result['updated_count'],
$result['comment_count']
)
)
);
}
if ( $result['failure'] ) {
wp_send_json_error( ['error' => __( 'Database error. Comments could not be cleared.', 'fictioneer' )] );
}
// Report success
wp_send_json_success(
array(
'success' => sprintf(
__( '%s comments have been cleared.', 'fictioneer' ),
$result['updated_count']
)
)
);
}
add_action( 'wp_ajax_fictioneer_ajax_clear_my_comments', 'fictioneer_ajax_clear_my_comments' );
@ -739,31 +735,29 @@ add_action( 'wp_ajax_fictioneer_ajax_clear_my_comments', 'fictioneer_ajax_clear_
// SELF-CLEAR USER COMMENT SUBSCRIPTIONS - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_clear_my_comment_subscriptions' ) ) {
/**
* Clears all the user's comment subscriptions via AJAX
*
* Changes the comment notification validation timestamp, effectively terminating
* all associated previous comment subscriptions. This is far cheaper than looping
* and updating all comments.
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Clears all the user's comment subscriptions via AJAX
*
* Changes the comment notification validation timestamp, effectively terminating
* all associated previous comment subscriptions. This is far cheaper than looping
* and updating all comments.
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_clear_my_comment_subscriptions() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_comment_subscriptions' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_clear_my_comment_subscriptions() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_clear_comment_subscriptions' );
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Change validator
if ( update_user_meta( $user->ID, 'fictioneer_comment_reply_validator', time() ) ) {
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Comment subscriptions could not be cleared.', 'fictioneer' )] );
}
// Change validator
if ( update_user_meta( $user->ID, 'fictioneer_comment_reply_validator', time() ) ) {
wp_send_json_success( ['success' => __( 'Data has been cleared.', 'fictioneer' )] );
} else {
wp_send_json_error( ['error' => __( 'Database error. Comment subscriptions could not be cleared.', 'fictioneer' )] );
}
}
add_action( 'wp_ajax_fictioneer_ajax_clear_my_comment_subscriptions', 'fictioneer_ajax_clear_my_comment_subscriptions' );
@ -772,78 +766,76 @@ add_action( 'wp_ajax_fictioneer_ajax_clear_my_comment_subscriptions', 'fictionee
// SELF-DELETE USER - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_delete_my_account' ) ) {
/**
* Delete an user's account via AJAX
*
* @since Fictioneer 4.5
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_validate_id()
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Delete an user's account via AJAX
*
* @since Fictioneer 4.5
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_validate_id()
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_delete_my_account() {
// Setup
$sender_id = isset( $_POST['id'] ) ? fictioneer_validate_id( $_POST['id'] ) : false;
$current_user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_delete_account' );
function fictioneer_ajax_delete_my_account() {
// Setup
$sender_id = isset( $_POST['id'] ) ? fictioneer_validate_id( $_POST['id'] ) : false;
$current_user = fictioneer_get_validated_ajax_user( 'nonce', 'fictioneer_delete_account' );
// Extra validations
if (
! $sender_id ||
! $current_user ||
$sender_id !== $current_user->ID ||
$current_user == 1 ||
in_array( 'administrator', $current_user->roles ) ||
current_user_can( 'edit_posts' ) ||
current_user_can( 'publish_posts' ) ||
current_user_can( 'moderate_comments' )
) {
wp_send_json_error(
array(
'error' => __( 'User role too high.', 'fictioneer' ),
'button' => __( 'Denied', 'fictioneer' )
)
);
die(); // Just to be sure
}
// Extra validations
if (
! $sender_id ||
! $current_user ||
$sender_id !== $current_user->ID ||
$current_user == 1 ||
in_array( 'administrator', $current_user->roles ) ||
current_user_can( 'edit_posts' ) ||
current_user_can( 'publish_posts' ) ||
current_user_can( 'moderate_comments' )
) {
wp_send_json_error(
array(
'error' => __( 'User role too high.', 'fictioneer' ),
'button' => __( 'Denied', 'fictioneer' )
)
);
die(); // Just to be sure
}
// Update comments
$comments = get_comments( array( 'user_id' => $current_user->ID ) );
// Update comments
$comments = get_comments( array( 'user_id' => $current_user->ID ) );
foreach ( $comments as $comment ) {
wp_update_comment(
array(
'comment_ID' => $comment->comment_ID,
'user_ID' => 0,
'comment_author' => fcntr( 'deleted_user' ),
'comment_author_email' => '',
'comment_author_IP' => '',
'comment_agent' => '',
'comment_author_url' => ''
)
);
foreach ( $comments as $comment ) {
wp_update_comment(
array(
'comment_ID' => $comment->comment_ID,
'user_ID' => 0,
'comment_author' => fcntr( 'deleted_user' ),
'comment_author_email' => '',
'comment_author_IP' => '',
'comment_agent' => '',
'comment_author_url' => ''
)
);
// Make absolutely sure no comment subscriptions remain
update_comment_meta( $comment->comment_ID, 'fictioneer_send_notifications', false );
// Make absolutely sure no comment subscriptions remain
update_comment_meta( $comment->comment_ID, 'fictioneer_send_notifications', false );
// Retain some (redacted) data in case there was a mistake
add_comment_meta( $comment->comment_ID, 'fictioneer_deleted_user_id', $current_user->ID );
add_comment_meta( $comment->comment_ID, 'fictioneer_deleted_username_substr', substr( $current_user->user_login, 0, 3 ) );
add_comment_meta( $comment->comment_ID, 'fictioneer_deleted_email_substr', substr( $comment->comment_author_email, 0, 3 ) );
}
// Retain some (redacted) data in case there was a mistake
add_comment_meta( $comment->comment_ID, 'fictioneer_deleted_user_id', $current_user->ID );
add_comment_meta( $comment->comment_ID, 'fictioneer_deleted_username_substr', substr( $current_user->user_login, 0, 3 ) );
add_comment_meta( $comment->comment_ID, 'fictioneer_deleted_email_substr', substr( $comment->comment_author_email, 0, 3 ) );
}
// Delete user
if ( wp_delete_user( $current_user->ID ) ) {
wp_send_json_success();
} else {
wp_send_json_error(
array(
'error' => __( 'Database error. Account could not be deleted.', 'fictioneer' ),
'button' => __( 'Failure', 'fictioneer' )
)
);
}
// Delete user
if ( wp_delete_user( $current_user->ID ) ) {
wp_send_json_success();
} else {
wp_send_json_error(
array(
'error' => __( 'Database error. Account could not be deleted.', 'fictioneer' ),
'button' => __( 'Failure', 'fictioneer' )
)
);
}
}
@ -855,24 +847,22 @@ if ( get_option( 'fictioneer_enable_subscriber_self_delete' ) ) {
// FETCH FINGERPRINT - AJAX
// =============================================================================
if ( ! function_exists( 'fictioneer_ajax_get_fingerprint' ) ) {
/**
* Sends the user's fingerprint via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
/**
* Sends the user's fingerprint via AJAX
*
* @since Fictioneer 5.0
* @link https://developer.wordpress.org/reference/functions/wp_send_json_success/
* @link https://developer.wordpress.org/reference/functions/wp_send_json_error/
* @see fictioneer_get_validated_ajax_user()
*/
function fictioneer_ajax_get_fingerprint() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
function fictioneer_ajax_get_fingerprint() {
// Setup and validations
$user = fictioneer_get_validated_ajax_user();
if ( ! $user ) wp_send_json_error( ['error' => __( 'Request did not pass validation.', 'fictioneer' )] );
// Response
wp_send_json_success( ['fingerprint' => fictioneer_get_user_fingerprint( $user->ID )] );
}
// Response
wp_send_json_success( ['fingerprint' => fictioneer_get_user_fingerprint( $user->ID )] );
}
add_action( 'wp_ajax_fictioneer_ajax_get_fingerprint', 'fictioneer_ajax_get_fingerprint' );

View File

@ -22,5 +22,71 @@ function fictioneer_display_render_time() {
}
// add_action( 'shutdown', 'fictioneer_display_render_time' );
// =============================================================================
// SHOW PATREON TIERS
// =============================================================================
/**
* Adds HTML for the Patreon tiers section to the wp-admin user profile
*
* DISABLED!
*
* @since Fictioneer 5.0
*
* @param WP_User $profile_user The profile user object. Not necessarily the one
* currently editing the profile!
*/
function fictioneer_admin_profile_patreon_tiers( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Start HTML ---> ?>
<tr class="user-patreon-tiers-wrap">
<th><label for="fictioneer_patreon_tiers"><?php _e( 'Patreon Tiers', 'fictioneer' ) ?></label></th>
<td>
<input name="fictioneer_patreon_tiers" type="text" id="fictioneer_patreon_tiers" value="<?php echo esc_attr( json_encode( get_the_author_meta( 'fictioneer_patreon_tiers', $profile_user->ID ) ) ); ?>" class="regular-text" readonly>
<p class="description"><?php _e( 'Patreon tiers for the linked Patreon client. Valid for two weeks after last login.', 'fictioneer' ) ?></p>
</td>
</tr>
<?php // <--- End HTML
}
// add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_patreon_tiers', 60 );
// =============================================================================
// SHOW BOOKMARKS SECTION
// =============================================================================
/**
* Adds HTML for the bookmarks section to the wp-admin user profile
*
* DISABLED!
*
* @since Fictioneer 5.0
*
* @param WP_User $profile_user The profile user object. Not necessarily the one
* currently editing the profile!
*/
function fictioneer_admin_profile_bookmarks( $profile_user ) {
// Setup
$editing_user_is_admin = fictioneer_is_admin( get_current_user_id() );
// Abort conditions...
if ( ! $editing_user_is_admin ) return;
// Start HTML ---> ?>
<tr class="user-bookmarks-wrap">
<th><label for="user_bookmarks"><?php _e( 'Bookmarks JSON', 'fictioneer' ) ?></label></th>
<td>
<textarea name="user_bookmarks" id="user_bookmarks" rows="12" cols="30" style="font-family: monospace; font-size: 12px; word-break: break-all;" disabled><?php echo esc_attr( get_the_author_meta( 'fictioneer_bookmarks', $profile_user->ID ) ); ?></textarea>
</td>
</tr>
<?php // <--- End HTML
}
// add_action( 'fictioneer_admin_user_sections', 'fictioneer_admin_profile_bookmarks', 70 );
?>