2596 lines
102 KiB
PHP
2596 lines
102 KiB
PHP
<?php
|
|
|
|
// =============================================================================
|
|
// GET SHORTCODE TRANSIENT
|
|
// =============================================================================
|
|
|
|
if ( ! function_exists( 'fictioneer_shortcode_query' ) ) {
|
|
/**
|
|
* Returns query for shortcode
|
|
*
|
|
* @since 5.4.9
|
|
*
|
|
* @param array $args Query arguments.
|
|
*
|
|
* @return WP_Query The query result.
|
|
*/
|
|
|
|
function fictioneer_shortcode_query( $args ) {
|
|
// Query
|
|
$result = new WP_Query( $args );
|
|
|
|
// Prime author cache
|
|
if (
|
|
get_option( 'fictioneer_show_authors' ) &&
|
|
! empty( $result->posts ) &&
|
|
function_exists( 'update_post_author_caches' )
|
|
) {
|
|
update_post_author_caches( $result->posts );
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// SHORTCODE-BASED RELATIONSHIPS
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Register relationships for posts with certain shortcodes
|
|
*
|
|
* @since 5.0.0
|
|
*
|
|
* @param int $post_id The ID of the saved post.
|
|
* @param WP_Post $post The saved post object.
|
|
*/
|
|
|
|
function fictioneer_update_shortcode_relationships( $post_id, $post ) {
|
|
// Prevent multi-fire
|
|
if ( fictioneer_multi_save_guard( $post_id ) ) {
|
|
return;
|
|
}
|
|
|
|
// Setup
|
|
$registry = fictioneer_get_relationship_registry();
|
|
|
|
// Look for blog shortcode
|
|
if ( str_contains( $post->post_content, 'fictioneer_blog' ) ) {
|
|
$registry['always'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['always'][ $post_id ] );
|
|
}
|
|
|
|
// Look for story data shortcode
|
|
if (
|
|
str_contains( $post->post_content, 'fictioneer_story_data' ) ||
|
|
str_contains( $post->post_content, 'fictioneer_story_comments' ) ||
|
|
str_contains( $post->post_content, 'fictioneer_story_actions' ) ||
|
|
str_contains( $post->post_content, 'fictioneer_story_section' ) ||
|
|
str_contains( $post->post_content, 'fictioneer_subscribe_button' )
|
|
) {
|
|
$registry['always'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['always'][ $post_id ] );
|
|
}
|
|
|
|
// Look for article cards shortcode
|
|
if ( str_contains( $post->post_content, 'fictioneer_article_cards' ) ) {
|
|
$registry['always'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['always'][ $post_id ] );
|
|
}
|
|
|
|
// Look for showcase shortcode
|
|
if ( str_contains( $post->post_content, 'fictioneer_showcase' ) ) {
|
|
$registry['always'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['always'][ $post_id ] );
|
|
}
|
|
|
|
// Look for post-related shortcode
|
|
if ( str_contains( $post->post_content, 'fictioneer_latest_posts' ) ) {
|
|
$registry['ref_posts'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['ref_posts'][ $post_id ] );
|
|
}
|
|
|
|
// Look for chapter-related shortcodes
|
|
if (
|
|
str_contains( $post->post_content, 'fictioneer_chapter_list' ) ||
|
|
str_contains( $post->post_content, 'fictioneer_latest_chapters' )
|
|
) {
|
|
$registry['ref_chapters'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['ref_chapters'][ $post_id ] );
|
|
}
|
|
|
|
// Look for story-related shortcodes
|
|
if (
|
|
str_contains( $post->post_content, 'fictioneer_latest_stories' ) ||
|
|
str_contains( $post->post_content, 'fictioneer_latest_updates' )
|
|
) {
|
|
$registry['ref_stories'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['ref_stories'][ $post_id ] );
|
|
}
|
|
|
|
// Look for recommendation-related shortcodes
|
|
if ( str_contains( $post->post_content, 'fictioneer_latest_recommendations' ) ) {
|
|
$registry['ref_recommendations'][ $post_id ] = 'shortcode';
|
|
} else {
|
|
unset( $registry['ref_recommendations'][ $post_id ] );
|
|
}
|
|
|
|
// Update database
|
|
fictioneer_save_relationship_registry( $registry );
|
|
}
|
|
|
|
if ( FICTIONEER_RELATIONSHIP_PURGE_ASSIST ) {
|
|
add_action( 'save_post', 'fictioneer_update_shortcode_relationships', 10, 2 );
|
|
}
|
|
|
|
// =============================================================================
|
|
// GET SHORTCODE DEFAULT ARGS
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Returns sanitized arguments extracted from shortcode attributes
|
|
*
|
|
* @since 5.7.3
|
|
*
|
|
* @param array $attr Attributes passed to the shortcode.
|
|
* @param int $def_count Default for the 'count' argument.
|
|
*
|
|
* @return array The extracted arguments.
|
|
*/
|
|
|
|
function fictioneer_get_default_shortcode_args( $attr, $def_count = -1 ) {
|
|
//--- Sanitize attributes ----------------------------------------------------
|
|
|
|
$attr = is_array( $attr ) ?
|
|
array_map( 'sanitize_text_field', $attr ) : sanitize_text_field( $attr );
|
|
|
|
//--- Extract arguments ------------------------------------------------------
|
|
|
|
$seamless_default = get_theme_mod( 'card_image_style', 'default' ) === 'seamless';
|
|
$thumbnail_default = get_theme_mod( 'card_image_style', 'default' ) !== 'none';
|
|
|
|
$uid = wp_unique_id( 'shortcode-id-' );
|
|
|
|
$args = array(
|
|
'uid' => $uid,
|
|
'type' => $attr['type'] ?? 'default',
|
|
'count' => max( -1, intval( $attr['count'] ?? $def_count ) ),
|
|
'offset' => max( 0, intval( $attr['offset'] ?? 0 ) ),
|
|
'order' => $attr['order'] ?? '',
|
|
'orderby' => $attr['orderby'] ?? '',
|
|
'page' => max( 1, get_query_var( 'page' ) ?: get_query_var( 'paged' ) ),
|
|
'posts_per_page' => absint( $attr['per_page'] ?? 0 ) ?: get_option( 'posts_per_page' ),
|
|
'post_status' => sanitize_key( $attr['post_status'] ?? 'publish' ),
|
|
'post_ids' => fictioneer_explode_list( $attr['post_ids'] ?? '' ),
|
|
'author' => sanitize_title( $attr['author'] ?? '' ),
|
|
'author_ids' => fictioneer_explode_list( $attr['author_ids'] ?? '' ),
|
|
'excluded_authors' => fictioneer_explode_list( $attr['exclude_author_ids'] ?? '' ),
|
|
'excluded_tags' => fictioneer_explode_list( $attr['exclude_tag_ids'] ?? '' ),
|
|
'excluded_cats' => fictioneer_explode_list( $attr['exclude_cat_ids'] ?? '' ),
|
|
'taxonomies' => fictioneer_get_shortcode_taxonomies( $attr ),
|
|
'relation' => strtolower( $attr['rel'] ?? 'and' ) === 'or' ? 'OR' : 'AND',
|
|
'ignore_sticky' => filter_var( $attr['ignore_sticky'] ?? 0, FILTER_VALIDATE_BOOLEAN ),
|
|
'ignore_protected' => filter_var( $attr['ignore_protected'] ?? 0, FILTER_VALIDATE_BOOLEAN ),
|
|
'only_protected' => filter_var( $attr['only_protected'] ?? 0, FILTER_VALIDATE_BOOLEAN ),
|
|
'vertical' => filter_var( $attr['vertical'] ?? 0, FILTER_VALIDATE_BOOLEAN ),
|
|
'seamless' => filter_var( $attr['seamless'] ?? $seamless_default, FILTER_VALIDATE_BOOLEAN ),
|
|
'aspect_ratio' => sanitize_css_aspect_ratio( $attr['aspect_ratio'] ?? '' ),
|
|
'thumbnail' => filter_var( $attr['thumbnail'] ?? $thumbnail_default, FILTER_VALIDATE_BOOLEAN ),
|
|
'lightbox' => filter_var( $attr['lightbox'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'words' => filter_var( $attr['words'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'date' => filter_var( $attr['date'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'date_format' => sanitize_text_field( $attr['date_format'] ?? '' ),
|
|
'nested_date_format' => sanitize_text_field( $attr['nested_date_format'] ?? '' ),
|
|
'footer' => filter_var( $attr['footer'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'footer_author' => filter_var( $attr['footer_author'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'footer_chapters' => filter_var( $attr['footer_chapters'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'footer_words' => filter_var( $attr['footer_words'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'footer_date' => filter_var( $attr['footer_date'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'footer_comments' => filter_var( $attr['footer_comments'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'footer_status' => filter_var( $attr['footer_status'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'footer_rating' => filter_var( $attr['footer_rating'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'classes' => esc_attr( wp_strip_all_tags( $attr['classes'] ?? $attr['class'] ?? '' ) ) . " {$uid}",
|
|
'infobox' => filter_var( $attr['infobox'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'source' => filter_var( $attr['source'] ?? 1, FILTER_VALIDATE_BOOLEAN ),
|
|
'splide' => sanitize_text_field( $attr['splide'] ?? '' ),
|
|
'cache' => filter_var( $attr['cache'] ?? 1, FILTER_VALIDATE_BOOLEAN )
|
|
);
|
|
|
|
//--- Fixes ------------------------------------------------------------------
|
|
|
|
// Update count if limited to post IDs
|
|
if ( ! empty( $args['post_ids'] ) ) {
|
|
$args['count'] = count( $args['post_ids'] );
|
|
}
|
|
|
|
// Prepare Splide JSON
|
|
if ( ! empty( $args['splide'] ) ) {
|
|
$args['splide'] = str_replace( "'", '"', $args['splide'] );
|
|
|
|
if ( ! fictioneer_is_valid_json( $args['splide'] ) ) {
|
|
$args['splide'] = false;
|
|
} else {
|
|
$splide = json_decode( $args['splide'], true );
|
|
|
|
// Turn arrows off by default
|
|
if ( ! preg_match( '/"arrows"\s*:\s*true/', $args['splide'] ) ) {
|
|
$splide['arrows'] = false;
|
|
}
|
|
|
|
// Change default arrow SVG path
|
|
if ( ! isset( $splide['arrowPath'] ) ) {
|
|
$splide['arrowPath'] = 'M31.89 18.24c0.98 0.98 0.98 2.56 0 3.54l-15 15c-0.98 0.98-2.56 0.98-3.54 0s-0.98-2.56 0-3.54L26.45 20 13.23 6.76c-0.98-0.98-0.98-2.56 0-3.54s2.56-0.98 3.54 0l15 15';
|
|
}
|
|
|
|
$args['splide'] = json_encode( $splide );
|
|
}
|
|
}
|
|
|
|
//--- Finish -----------------------------------------------------------------
|
|
|
|
return $args;
|
|
}
|
|
|
|
// =============================================================================
|
|
// GET SHORTCODE TAXONOMIES
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Extract taxonomies from shortcode attributes
|
|
*
|
|
* @since 5.2.0
|
|
*
|
|
* @param array $attr Attributes of the shortcode.
|
|
*
|
|
* @return array Array of found taxonomies.
|
|
*/
|
|
|
|
function fictioneer_get_shortcode_taxonomies( $attr ) {
|
|
// Setup
|
|
$taxonomies = [];
|
|
|
|
// Tags
|
|
if ( ! empty( $attr['tags'] ) ) {
|
|
$taxonomies['tags'] = fictioneer_explode_list( $attr['tags'] );
|
|
}
|
|
|
|
// Categories
|
|
if ( ! empty( $attr['categories'] ) ) {
|
|
$taxonomies['categories'] = fictioneer_explode_list( $attr['categories'] );
|
|
}
|
|
|
|
// Fandoms
|
|
if ( ! empty( $attr['fandoms'] ) ) {
|
|
$taxonomies['fandoms'] = fictioneer_explode_list( $attr['fandoms'] );
|
|
}
|
|
|
|
// Characters
|
|
if ( ! empty( $attr['characters'] ) ) {
|
|
$taxonomies['characters'] = fictioneer_explode_list( $attr['characters'] );
|
|
}
|
|
|
|
// Genres
|
|
if ( ! empty( $attr['genres'] ) ) {
|
|
$taxonomies['genres'] = fictioneer_explode_list( $attr['genres'] );
|
|
}
|
|
|
|
// Return
|
|
return $taxonomies;
|
|
}
|
|
|
|
// =============================================================================
|
|
// GET SHORTCODE TAX QUERY
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Get shortcode Tax Query
|
|
*
|
|
* @since 5.2.0
|
|
*
|
|
* @param array $args Arguments of the shortcode partial.
|
|
*
|
|
* @return array Tax Query.
|
|
*/
|
|
|
|
function fictioneer_get_shortcode_tax_query( $args ) {
|
|
// Setup
|
|
$tax_query = [];
|
|
|
|
// Are there taxonomies?
|
|
if ( ! empty( $args['taxonomies'] ) ) {
|
|
// Relationship?
|
|
if ( count( $args['taxonomies'] ) > 1 ) {
|
|
$tax_query['relation'] = $args['relation'];
|
|
}
|
|
|
|
// Tags?
|
|
if ( ! empty( $args['taxonomies']['tags'] ) ) {
|
|
$tax_query[] = array(
|
|
'taxonomy' => 'post_tag',
|
|
'field' => 'name',
|
|
'terms' => $args['taxonomies']['tags']
|
|
);
|
|
}
|
|
|
|
// Categories?
|
|
if ( ! empty( $args['taxonomies']['categories'] ) ) {
|
|
$tax_query[] = array(
|
|
'taxonomy' => 'category',
|
|
'field' => 'name',
|
|
'terms' => $args['taxonomies']['categories']
|
|
);
|
|
}
|
|
|
|
// Fandoms?
|
|
if ( ! empty( $args['taxonomies']['fandoms'] ) ) {
|
|
$tax_query[] = array(
|
|
'taxonomy' => 'fcn_fandom',
|
|
'field' => 'name',
|
|
'terms' => $args['taxonomies']['fandoms']
|
|
);
|
|
}
|
|
|
|
// Characters?
|
|
if ( ! empty( $args['taxonomies']['characters'] ) ) {
|
|
$tax_query[] = array(
|
|
'taxonomy' => 'fcn_character',
|
|
'field' => 'name',
|
|
'terms' => $args['taxonomies']['characters']
|
|
);
|
|
}
|
|
|
|
// Genres?
|
|
if ( ! empty( $args['taxonomies']['genres'] ) ) {
|
|
$tax_query[] = array(
|
|
'taxonomy' => 'fcn_genre',
|
|
'field' => 'name',
|
|
'terms' => $args['taxonomies']['genres']
|
|
);
|
|
}
|
|
}
|
|
|
|
// Return
|
|
return $tax_query;
|
|
}
|
|
|
|
// =============================================================================
|
|
// SPLIDE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Returns inline script to initialize Splide ASAP
|
|
*
|
|
* Note: The script tag is only returned once in case multiple sliders
|
|
* are active since only one is needed.
|
|
*
|
|
* @since 5.25.0
|
|
* @since 5.26.1 - Use wp_print_inline_script_tag().
|
|
*
|
|
* @return string The inline script.
|
|
*/
|
|
|
|
function fictioneer_get_splide_inline_init() {
|
|
static $done = null;
|
|
|
|
if ( $done ) {
|
|
return '';
|
|
}
|
|
|
|
$done = true;
|
|
|
|
return wp_get_inline_script_tag(
|
|
'document.addEventListener("DOMContentLoaded",()=>{document.querySelectorAll(".splide:not(.no-auto-splide, .is-initialized)").forEach(e=>{e.querySelector(".splide__list")&&"undefined"!=typeof Splide&&(e.classList.remove("_splide-placeholder"),new Splide(e).mount())})});',
|
|
array(
|
|
'id' => 'fictioneer-iife-splide',
|
|
'class' => 'temp-script',
|
|
'type' => 'text/javascript',
|
|
'data-jetpack-boost' => 'ignore',
|
|
'data-no-optimize' => '1',
|
|
'data-no-defer' => '1',
|
|
'data-no-minify' => '1'
|
|
)
|
|
);
|
|
}
|
|
|
|
// =============================================================================
|
|
// SHOWCASE SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to display showcase
|
|
*
|
|
* @since 5.0.0
|
|
*
|
|
* @param string $attr['for'] What the showcase is for. Allowed are chapters,
|
|
* collections, recommendations, and stories.
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default 8.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['order'] Optional. Order direction. Default 'DESC'.
|
|
* @param string|null $attr['orderby'] Optional. Order argument. Default 'date'.
|
|
* @param string|null $attr['post_ids'] Optional. Limit posts to specific post IDs.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['fandoms'] Optional. Limit posts to specific fandom names.
|
|
* @param string|null $attr['genres'] Optional. Limit posts to specific genre names.
|
|
* @param string|null $attr['characters'] Optional. Limit posts to specific character names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['vertical'] Optional. Whether to show the vertical variant.
|
|
* @param string|null $attr['seamless'] Optional. Whether to render the image seamless. Default false (Customizer).
|
|
* @param string|null $attr['aspect_ratio'] Optional. Aspect ratio of the item. Default empty.
|
|
* @param string|null $attr['height'] Optional. Override the item height. Default empty.
|
|
* @param string|null $attr['min_width'] Optional. Override the item minimum width. Default empty.
|
|
* @param string|null $attr['lightbox'] Optional. Whether the thumbnail is opened in the lightbox. Default true.
|
|
* @param string|null $attr['thumbnail'] Optional. Whether to show the thumbnail. Default true (Customizer).
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $args['splide'] Optional. Configuration JSON for the Splide slider. Default empty.
|
|
* @param string|null $args['quality'] Optional. Size of the images. Default 'medium'.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_showcase( $attr ) {
|
|
// Abort if...
|
|
if ( empty( $attr['for'] ) ) {
|
|
return '';
|
|
}
|
|
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr, 8 );
|
|
|
|
// Height/Width/Quality
|
|
$args['height'] = sanitize_text_field( $attr['height'] ?? '' );
|
|
$args['min_width'] = sanitize_text_field( $attr['min_width'] ?? '' );
|
|
$args['quality'] = sanitize_text_field( $attr['quality'] ?? 'medium' );
|
|
|
|
// Specifics
|
|
$args['no_cap'] = filter_var( $attr['no_cap'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
|
|
switch ( $attr['for'] ) {
|
|
case 'collections':
|
|
$args['post_type'] = 'fcn_collection';
|
|
break;
|
|
case 'chapters':
|
|
$args['post_type'] = 'fcn_chapter';
|
|
break;
|
|
case 'stories':
|
|
$args['post_type'] = 'fcn_story';
|
|
break;
|
|
case 'recommendations':
|
|
$args['post_type'] = 'fcn_recommendation';
|
|
break;
|
|
}
|
|
|
|
// Abort if...
|
|
if ( ! isset( $args['post_type'] ) ) {
|
|
return '';
|
|
}
|
|
|
|
// Extra classes
|
|
if ( $args['splide'] ?? 0 ) {
|
|
$args['classes'] .= ' splide _splide-placeholder';
|
|
}
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_showcase' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $args ) . serialize( $attr );
|
|
$type = $args['post_type'];
|
|
$transient_key = "fictioneer_shortcode_showcase_{$type}_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
get_template_part( 'partials/_showcase', null, $args );
|
|
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( ( $args['splide'] ?? 0 ) && strpos( $args['classes'], 'no-auto-splide' ) === false ) {
|
|
$html .= fictioneer_get_splide_inline_init();
|
|
}
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_showcase', 'fictioneer_shortcode_showcase' );
|
|
|
|
// =============================================================================
|
|
// LATEST CHAPTERS SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show latest chapters
|
|
*
|
|
* @since 3.0
|
|
*
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default 4.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['type'] Optional. Choose between 'default', 'simple', and 'compact'.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['order'] Optional. Order argument. Default 'DESC'.
|
|
* @param string|null $attr['orderby'] Optional. Orderby argument. Default 'date'.
|
|
* @param string|null $attr['spoiler'] Optional. Whether to show spoiler content.
|
|
* @param string|null $attr['source'] Optional. Whether to show the author and story.
|
|
* @param string|null $attr['post_ids'] Optional. Limit posts to specific post IDs.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['fandoms'] Optional. Limit posts to specific fandom names.
|
|
* @param string|null $attr['genres'] Optional. Limit posts to specific genre names.
|
|
* @param string|null $attr['characters'] Optional. Limit posts to specific character names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['vertical'] Optional. Whether to show the vertical variant.
|
|
* @param string|null $attr['seamless'] Optional. Whether to render the image seamless. Default false (Customizer).
|
|
* @param string|null $attr['aspect_ratio'] Optional. Aspect ratio for the image. Only with vertical.
|
|
* @param string|null $attr['lightbox'] Optional. Whether the thumbnail is opened in the lightbox. Default true.
|
|
* @param string|null $attr['thumbnail'] Optional. Whether to show the thumbnail. Default true (Customizer).
|
|
* @param string|null $attr['date_format'] Optional. String to override the date format. Default empty.
|
|
* @param string|null $attr['footer'] Optional. Whether to show the footer (if any). Default true.
|
|
* @param string|null $attr['footer_author'] Optional. Whether to show the chapter author. Default true.
|
|
* @param string|null $attr['footer_date'] Optional. Whether to show the chapter date. Default true.
|
|
* @param string|null $attr['footer_words'] Optional. Whether to show the chapter word count. Default true.
|
|
* @param string|null $attr['footer_comments'] Optional. Whether to show the chapter comment count. Default true.
|
|
* @param string|null $attr['footer_status'] Optional. Whether to show the chapter status. Default true.
|
|
* @param string|null $attr['footer_rating'] Optional. Whether to show the story/chapter age rating. Default true.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $args['splide'] Configuration JSON for the Splide slider. Default empty.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_latest_chapters( $attr ) {
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr, 4 );
|
|
|
|
// Specifics
|
|
$args['simple'] = false;
|
|
$args['spoiler'] = filter_var( $attr['spoiler'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
|
|
// Type
|
|
$type = sanitize_text_field( $attr['type'] ?? 'default' );
|
|
|
|
// Extra classes
|
|
if ( $args['splide'] ?? 0 ) {
|
|
$args['classes'] .= ' splide _splide-placeholder';
|
|
}
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_latest_chapters' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $args ) . serialize( $attr );
|
|
$transient_key = "fictioneer_shortcode_latest_chapters_{$type}_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
switch ( $type ) {
|
|
case 'compact':
|
|
get_template_part( 'partials/_latest-chapters-compact', null, $args );
|
|
break;
|
|
case 'list':
|
|
get_template_part( 'partials/_latest-chapters-list', null, $args );
|
|
break;
|
|
default:
|
|
$args['simple'] = $type == 'simple';
|
|
get_template_part( 'partials/_latest-chapters', null, $args );
|
|
}
|
|
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( ( $args['splide'] ?? 0 ) && strpos( $args['classes'], 'no-auto-splide' ) === false ) {
|
|
$html .= fictioneer_get_splide_inline_init();
|
|
}
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_latest_chapters', 'fictioneer_shortcode_latest_chapters' );
|
|
|
|
// =============================================================================
|
|
// LATEST STORIES SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show latest stories
|
|
*
|
|
* @since 3.0
|
|
*
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default 4.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['type'] Optional. Choose between 'default' and 'compact'.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['order'] Optional. Order argument. Default 'DESC'.
|
|
* @param string|null $attr['orderby'] Optional. Orderby argument. Default 'date'.
|
|
* @param string|null $attr['post_ids'] Optional. Limit posts to specific post IDs.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['fandoms'] Optional. Limit posts to specific fandom names.
|
|
* @param string|null $attr['genres'] Optional. Limit posts to specific genre names.
|
|
* @param string|null $attr['characters'] Optional. Limit posts to specific character names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['vertical'] Optional. Whether to show the vertical variant.
|
|
* @param string|null $attr['seamless'] Optional. Whether to render the image seamless. Default false (Customizer).
|
|
* @param string|null $attr['aspect_ratio'] Optional. Aspect ratio for the image. Only with vertical.
|
|
* @param string|null $attr['lightbox'] Optional. Whether the thumbnail is opened in the lightbox. Default true.
|
|
* @param string|null $attr['thumbnail'] Optional. Whether to show the thumbnail. Default true (Customizer).
|
|
* @param string|null $attr['date_format'] Optional. String to override the date format. Default empty.
|
|
* @param string|null $attr['terms'] Optional. Either 'inline', 'pills', 'none', or 'false' (only in list type).
|
|
* Default 'inline'.
|
|
* @param string|null $attr['max_terms'] Optional. Maximum number of shown taxonomies. Default 10.
|
|
* @param string|null $attr['footer'] Optional. Whether to show the footer (if any). Default true.
|
|
* @param string|null $attr['footer_author'] Optional. Whether to show the story author. Default true.
|
|
* @param string|null $attr['footer_date'] Optional. Whether to show the story date. Default true.
|
|
* @param string|null $attr['footer_words'] Optional. Whether to show the story word count. Default true.
|
|
* @param string|null $attr['footer_chapters'] Optional. Whether to show the story chapter count. Default true.
|
|
* @param string|null $attr['footer_status'] Optional. Whether to show the story status. Default true.
|
|
* @param string|null $attr['footer_rating'] Optional. Whether to show the story age rating. Default true.
|
|
* @param string|null $attr['footer_comments'] Optional. Whether to show the post comment count. Default false.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $args['splide'] Configuration JSON for the Splide slider. Default empty.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_latest_stories( $attr ) {
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr, 4 );
|
|
|
|
// Type
|
|
$type = sanitize_text_field( $attr['type'] ?? 'default' );
|
|
|
|
// Comments
|
|
$args['footer_comments'] = filter_var( $attr['footer_comments'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
|
|
// Terms
|
|
$args['terms'] = fictioneer_sanitize_query_var( $attr['terms'] ?? 0, ['inline', 'pills', 'none', 'false'], 'inline' );
|
|
$args['max_terms'] = absint( ( $attr['max_terms'] ?? 10 ) ?: 10 );
|
|
|
|
// Extra classes
|
|
if ( $args['splide'] ?? 0 ) {
|
|
$args['classes'] .= ' splide _splide-placeholder';
|
|
}
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_latest_stories' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $args ) . serialize( $attr );
|
|
$transient_key = "fictioneer_shortcode_latest_stories_{$type}_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
switch ( $type ) {
|
|
case 'compact':
|
|
get_template_part( 'partials/_latest-stories-compact', null, $args );
|
|
break;
|
|
case 'list':
|
|
get_template_part( 'partials/_latest-stories-list', null, $args );
|
|
break;
|
|
default:
|
|
get_template_part( 'partials/_latest-stories', null, $args );
|
|
}
|
|
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( ( $args['splide'] ?? 0 ) && strpos( $args['classes'], 'no-auto-splide' ) === false ) {
|
|
$html .= fictioneer_get_splide_inline_init();
|
|
}
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_latest_stories', 'fictioneer_shortcode_latest_stories' );
|
|
|
|
// =============================================================================
|
|
// LATEST UPDATES SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show latest story updates
|
|
*
|
|
* @since 4.3.0
|
|
*
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default 4.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['type'] Optional. Choose between 'default', 'simple', 'single', and 'compact'.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['single'] Optional. Whether to show only one chapter item. Default false.
|
|
* @param string|null $attr['post_ids'] Optional. Limit posts to specific post IDs.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['fandoms'] Optional. Limit posts to specific fandom names.
|
|
* @param string|null $attr['genres'] Optional. Limit posts to specific genre names.
|
|
* @param string|null $attr['characters'] Optional. Limit posts to specific character names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['vertical'] Optional. Whether to show the vertical variant.
|
|
* @param string|null $attr['seamless'] Optional. Whether to render the image seamless. Default false (Customizer).
|
|
* @param string|null $attr['aspect_ratio'] Optional. Aspect ratio for the image. Only with vertical.
|
|
* @param string|null $attr['lightbox'] Optional. Whether the thumbnail is opened in the lightbox. Default true.
|
|
* @param string|null $attr['thumbnail'] Optional. Whether to show the thumbnail. Default true (Customizer).
|
|
* @param string|null $attr['words'] Optional. Whether to show the word count of chapter items. Default true.
|
|
* @param string|null $attr['date'] Optional. Whether to show the date of chapter items. Default true.
|
|
* @param string|null $attr['date_format'] Optional. String to override the date format. Default empty.
|
|
* @param string|null $attr['nested_date_format'] Optional. String to override any nested date formats. Default empty.
|
|
* @param string|null $attr['terms'] Optional. Either 'inline', 'pills', 'none', or 'false' (only in list type).
|
|
* Default 'inline'.
|
|
* @param string|null $attr['max_terms'] Optional. Maximum number of shown taxonomies. Default 10.
|
|
* @param string|null $attr['footer'] Optional. Whether to show the footer (if any). Default true.
|
|
* @param string|null $attr['footer_author'] Optional. Whether to show the story author. Default true.
|
|
* @param string|null $attr['footer_date'] Optional. Whether to show the story date. Default true.
|
|
* @param string|null $attr['footer_words'] Optional. Whether to show the story word count. Default true.
|
|
* @param string|null $attr['footer_chapters'] Optional. Whether to show the story chapter count. Default true.
|
|
* @param string|null $attr['footer_status'] Optional. Whether to show the story status. Default true.
|
|
* @param string|null $attr['footer_rating'] Optional. Whether to show the story/chapter age rating. Default true.
|
|
* @param string|null $attr['footer_comments'] Optional. Whether to show the post comment count. Default false.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $args['splide'] Configuration JSON for the Splide slider. Default empty.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_latest_story_updates( $attr ) {
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr, 4 );
|
|
$args['single'] = filter_var( $attr['single'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
|
|
// Comments
|
|
$args['footer_comments'] = filter_var( $attr['footer_comments'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
|
|
// Type
|
|
$type = sanitize_text_field( $attr['type'] ?? 'default' );
|
|
|
|
// Terms
|
|
$args['terms'] = fictioneer_sanitize_query_var( $attr['terms'] ?? 0, ['inline', 'pills', 'none', 'false'], 'inline' );
|
|
$args['max_terms'] = absint( ( $attr['max_terms'] ?? 10 ) ?: 10 );
|
|
|
|
// Extra classes
|
|
if ( $args['splide'] ?? 0 ) {
|
|
$args['classes'] .= ' splide _splide-placeholder ';
|
|
}
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_latest_updates' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $args ) . serialize( $attr );
|
|
$transient_key = "fictioneer_shortcode_latest_updates_{$type}_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
switch ( $type ) {
|
|
case 'compact':
|
|
get_template_part( 'partials/_latest-updates-compact', null, $args );
|
|
break;
|
|
case 'list':
|
|
get_template_part( 'partials/_latest-updates-list', null, $args );
|
|
break;
|
|
default:
|
|
get_template_part( 'partials/_latest-updates', null, $args );
|
|
}
|
|
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( ( $args['splide'] ?? 0 ) && strpos( $args['classes'], 'no-auto-splide' ) === false ) {
|
|
$html .= fictioneer_get_splide_inline_init();
|
|
}
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_latest_updates', 'fictioneer_shortcode_latest_story_updates' );
|
|
|
|
// =============================================================================
|
|
// LATEST RECOMMENDATIONS SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show latest recommendations
|
|
*
|
|
* @since 4.0.0
|
|
*
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default 4.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['type'] Optional. Choose between 'default' and 'compact'.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['order'] Optional. Order argument. Default 'DESC'.
|
|
* @param string|null $attr['orderby'] Optional. Orderby argument. Default 'date'.
|
|
* @param string|null $attr['post_ids'] Optional. Limit posts to specific post IDs.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['fandoms'] Optional. Limit posts to specific fandom names.
|
|
* @param string|null $attr['genres'] Optional. Limit posts to specific genre names.
|
|
* @param string|null $attr['characters'] Optional. Limit posts to specific character names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['vertical'] Optional. Whether to show the vertical variant.
|
|
* @param string|null $attr['seamless'] Optional. Whether to render the image seamless. Default false (Customizer).
|
|
* @param string|null $attr['aspect_ratio'] Optional. Aspect ratio for the image. Only with vertical.
|
|
* @param string|null $attr['lightbox'] Optional. Whether the thumbnail is opened in the lightbox. Default true.
|
|
* @param string|null $attr['thumbnail'] Optional. Whether to show the thumbnail. Default true (Customizer).
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $args['splide'] Configuration JSON for the Splide slider. Default empty.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_latest_recommendations( $attr ) {
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr, 4 );
|
|
|
|
// Type
|
|
$type = sanitize_text_field( $attr['type'] ?? 'default' );
|
|
|
|
// Terms
|
|
$args['terms'] = fictioneer_sanitize_query_var( $attr['terms'] ?? 0, ['inline', 'pills', 'none', 'false'], 'inline' );
|
|
$args['max_terms'] = absint( ( $attr['max_terms'] ?? 10 ) ?: 10 );
|
|
|
|
// Extra classes
|
|
if ( $args['splide'] ?? 0 ) {
|
|
$args['classes'] .= ' splide _splide-placeholder';
|
|
}
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_latest_recommendations' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $args ) . serialize( $attr );
|
|
$transient_key = "fictioneer_shortcode_latest_recommendations_{$type}_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
switch ( $type ) {
|
|
case 'compact':
|
|
get_template_part( 'partials/_latest-recommendations-compact', null, $args );
|
|
break;
|
|
default:
|
|
get_template_part( 'partials/_latest-recommendations', null, $args );
|
|
}
|
|
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( ( $args['splide'] ?? 0 ) && strpos( $args['classes'], 'no-auto-splide' ) === false ) {
|
|
$html .= fictioneer_get_splide_inline_init();
|
|
}
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_latest_recommendations', 'fictioneer_shortcode_latest_recommendations' );
|
|
|
|
// =============================================================================
|
|
// LATEST POST SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show the latest post
|
|
*
|
|
* @since 4.0.0
|
|
*
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default 1.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['post_ids'] Optional. Limit posts to specific post IDs.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_latest_posts( $attr ) {
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr, 1 );
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_latest_posts' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $args ) . serialize( $attr );
|
|
$transient_key = "fictioneer_shortcode_latest_posts_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
get_template_part( 'partials/_latest-posts', null, $args );
|
|
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_latest_posts', 'fictioneer_shortcode_latest_posts' );
|
|
|
|
// =============================================================================
|
|
// BOOKMARKS SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show bookmarks
|
|
*
|
|
* @since 4.0.0
|
|
*
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default -1 (all).
|
|
* @param string|null $attr['show_empty'] Optional. Whether to show the "no bookmarks" message. Default false.
|
|
* @param string|null $attr['seamless'] Optional. Whether to render the image seamless. Default false (Customizer).
|
|
* @param string|null $attr['thumbnail'] Optional. Whether to show the thumbnail. Default true (Customizer).
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_bookmarks( $attr ) {
|
|
// Sanitize attributes
|
|
$attr = is_array( $attr ) ? array_map( 'sanitize_text_field', $attr ) : sanitize_text_field( $attr );
|
|
|
|
// Setup
|
|
$seamless_default = get_theme_mod( 'card_image_style', 'default' ) === 'seamless';
|
|
$thumbnail_default = get_theme_mod( 'card_image_style', 'default' ) !== 'none';
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
get_template_part( 'partials/_bookmarks', null, array(
|
|
'count' => max( -1, intval( $attr['count'] ?? -1 ) ),
|
|
'show_empty' => $attr['show_empty'] ?? false,
|
|
'seamless' => filter_var( $attr['seamless'] ?? $seamless_default, FILTER_VALIDATE_BOOLEAN ),
|
|
'thumbnail' => filter_var( $attr['thumbnail'] ?? $thumbnail_default, FILTER_VALIDATE_BOOLEAN )
|
|
));
|
|
|
|
// Return minified buffer
|
|
return fictioneer_minify_html( ob_get_clean() );
|
|
}
|
|
add_shortcode( 'fictioneer_bookmarks', 'fictioneer_shortcode_bookmarks' );
|
|
|
|
// =============================================================================
|
|
// COOKIES SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show cookie consent actions
|
|
*
|
|
* Renders buttons to handle your consent and stored cookies.
|
|
*
|
|
* @since 4.7.0
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_cookie_buttons( $attr ) {
|
|
ob_start();
|
|
|
|
// Start HTML ---> ?>
|
|
<div class="cookies spacing-top spacing-bottom ">
|
|
<button type="button" data-action="click->fictioneer#clearConsent" class="button"><?php _e( 'Reset Consent', 'fictioneer' ); ?></button>
|
|
<button type="button" data-action="click->fictioneer#clearCookies" data-message="<?php _e( 'Cookies and local storage have been cleared. To keep it that way, you should leave the site.', 'fictioneer' ); ?>" class="button"><?php _e( 'Clear Cookies', 'fictioneer' ); ?></button>
|
|
</div>
|
|
<?php // <--- End HTML
|
|
|
|
return fictioneer_minify_html( ob_get_clean() );
|
|
}
|
|
add_shortcode( 'fictioneer_cookie_buttons', 'fictioneer_shortcode_cookie_buttons' );
|
|
|
|
// =============================================================================
|
|
// CHAPTER LIST SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Returns empty chapter list
|
|
*
|
|
* @since 5.9.4
|
|
*
|
|
* @param string|null $attr['heading'] Optional. Show <h5> heading above list.
|
|
*
|
|
* @return string The captured HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_chapter_list_empty( $attr ) {
|
|
ob_start();
|
|
|
|
// Start HTML ---> ?>
|
|
<div class="chapter-group chapter-list _standalone _empty">
|
|
<?php if ( ! empty( $attr['heading'] ) ) : ?>
|
|
<button class="chapter-group__name" data-action="click->fictioneer#toggleChapterGroup" aria-label="<?php echo esc_attr( sprintf( __( 'Toggle chapter group: %s', 'fictioneer' ), $attr['heading'] ) ); ?>" tabindex="0">
|
|
<i class="fa-solid fa-chevron-down chapter-group__heading-icon"></i>
|
|
<span><?php echo $attr['heading']; ?></span>
|
|
</button>
|
|
<?php endif; ?>
|
|
<ol class="chapter-group__list">
|
|
<li class="chapter-group__list-item _empty"><?php _e( 'No chapters published yet.', 'fictioneer' ); ?></li>
|
|
</ol>
|
|
</div>
|
|
<?php // <--- End HTML
|
|
|
|
return fictioneer_minify_html( ob_get_clean() );
|
|
}
|
|
|
|
/**
|
|
* Shortcode to show chapter list outside of story pages
|
|
*
|
|
* @since 5.0.0
|
|
*
|
|
* @param string $attr['story_id'] Either/Or. The ID of the story the chapters belong to.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['chapter_ids'] Either/Or. Comma-separated list of chapter IDs.
|
|
* @param string|null $attr['count'] Optional. Maximum number of items. Default -1 (all).
|
|
* @param string|null $attr['offset'] Optional. Skip a number of posts.
|
|
* @param string|null $attr['group'] Optional. Only show chapters of the group.
|
|
* @param string|null $attr['heading'] Optional. Show <h5> heading above list.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_chapter_list( $attr ) {
|
|
// Sanitize attributes
|
|
$attr = is_array( $attr ) ? array_map( 'sanitize_text_field', $attr ) : sanitize_text_field( $attr );
|
|
|
|
// Return empty case if...
|
|
if ( empty( $attr['story_id'] ) && empty( $attr['chapter_ids'] ) ) {
|
|
return fictioneer_shortcode_chapter_list_empty( $attr );
|
|
}
|
|
|
|
// Setup
|
|
$cache = filter_var( $attr['cache'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$count = max( -1, intval( $attr['count'] ?? -1 ) );
|
|
$offset = max( 0, intval( $attr['offset'] ?? 0 ) );
|
|
$group = empty( $attr['group'] ) ? false : strtolower( trim( $attr['group'] ) );
|
|
$heading = empty( $attr['heading'] ) ? false : $attr['heading'];
|
|
$post_status = sanitize_key( $attr['post_status'] ?? 'publish' );
|
|
$story_id = fictioneer_validate_id( $attr['story_id'] ?? -1, 'fcn_story' );
|
|
$prefer_chapter_icon = get_option( 'fictioneer_override_chapter_status_icons' );
|
|
$hide_icons = get_option( 'fictioneer_hide_chapter_icons' );
|
|
$can_checkmarks = get_option( 'fictioneer_enable_checkmarks' ) && ( is_user_logged_in() || get_option( 'fictioneer_enable_ajax_authentication' ) );
|
|
$classes = wp_strip_all_tags( $attr['class'] ?? '' );
|
|
$chapter_ids = [];
|
|
$chapters = [];
|
|
|
|
// Extract chapter IDs (if any)
|
|
if ( ! empty( $attr['chapter_ids'] ) ) {
|
|
$chapter_ids = fictioneer_explode_list( $attr['chapter_ids'] );
|
|
}
|
|
|
|
// Get chapters...
|
|
if ( $story_id && empty( $chapter_ids ) ) {
|
|
// ... via story
|
|
$hide_icons = $hide_icons || get_post_meta( $story_id, 'fictioneer_story_hide_chapter_icons', true );
|
|
$story_data = fictioneer_get_story_data( $story_id, false ); // Does not refresh comment count!
|
|
$chapters = $story_data['chapter_ids'];
|
|
} elseif ( ! empty( $chapter_ids ) ) {
|
|
// ... via chapter IDs
|
|
$chapters = $chapter_ids;
|
|
}
|
|
|
|
// Extra classes
|
|
if ( $hide_icons ) {
|
|
$classes .= ' _no-icons';
|
|
}
|
|
|
|
if ( get_option( 'fictioneer_collapse_groups_by_default' ) && ! str_contains( $classes, 'no-auto-collapse' ) ) {
|
|
$classes .= ' _closed';
|
|
}
|
|
|
|
// Apply offset and count
|
|
if ( ! $group ) {
|
|
$chapters = array_slice( $chapters, $offset );
|
|
$chapters = $count > 0 ? array_slice( $chapters, 0, $count ) : $chapters;
|
|
}
|
|
|
|
// Return empty case if...
|
|
if ( empty( $chapters ) ) {
|
|
return fictioneer_shortcode_chapter_list_empty( $attr );
|
|
}
|
|
|
|
// Query chapters
|
|
$query_args = array(
|
|
'fictioneer_query_name' => 'fictioneer_shortcode_chapter_list',
|
|
'post_type' => 'fcn_chapter',
|
|
'post_status' => $post_status,
|
|
'post__in' => $chapters, // Cannot be empty!
|
|
'ignore_sticky_posts' => true,
|
|
'orderby' => 'post__in', // Preserve order from meta box
|
|
'posts_per_page' => -1, // Get all chapters (this can be hundreds)
|
|
'no_found_rows' => true, // Improve performance
|
|
'update_post_term_cache' => false // Improve performance
|
|
);
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_chapter_list' );
|
|
|
|
if ( $transient_enabled && $cache ) {
|
|
$base = serialize( $query_args ) . serialize( $attr ) . $classes;
|
|
$base .= ( $hide_icons ? '1' : '0' ) . ( $can_checkmarks ? '1' : '0' );
|
|
$transient_key = "fictioneer_shortcode_chapter_list_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Query
|
|
$chapter_query = fictioneer_shortcode_query( $query_args );
|
|
|
|
// Return empty case if...
|
|
if ( ! $chapter_query->have_posts() ) {
|
|
return fictioneer_shortcode_chapter_list_empty( $attr );
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
// Start HTML ---> ?>
|
|
<div class="chapter-group chapter-list _standalone <?php echo esc_attr( $classes ); ?>">
|
|
<?php if ( $heading ) : ?>
|
|
<button class="chapter-group__name" data-action="click->fictioneer#toggleChapterGroup" aria-label="<?php echo esc_attr( sprintf( __( 'Toggle chapter group: %s', 'fictioneer' ), $heading ) ); ?>" tabindex="0">
|
|
<i class="fa-solid fa-chevron-down chapter-group__heading-icon"></i>
|
|
<span><?php echo $heading; ?></span>
|
|
</button>
|
|
<?php endif; ?>
|
|
<ol class="chapter-group__list">
|
|
<?php
|
|
$render_count = 0;
|
|
|
|
global $post;
|
|
|
|
while( $chapter_query->have_posts() ) {
|
|
// Setup
|
|
$chapter_query->the_post();
|
|
$chapter_id = get_the_ID();
|
|
$chapter_story_id = fictioneer_get_chapter_story_id( $chapter_id );
|
|
|
|
// Skip not visible chapters
|
|
if ( get_post_meta( $chapter_id, 'fictioneer_chapter_hidden', true ) ) {
|
|
continue;
|
|
}
|
|
|
|
// Check group (if any)
|
|
if ( $group && $group != strtolower( trim( get_post_meta( $chapter_id, 'fictioneer_chapter_group', true ) ) ) ) {
|
|
continue;
|
|
}
|
|
|
|
// Count renderings
|
|
$render_count++;
|
|
|
|
// Apply offset if limited to group (not working in query for 'posts_per_page' => -1)
|
|
if ( $group && $offset > 0 && $render_count <= $offset ) {
|
|
continue;
|
|
}
|
|
|
|
// Apply count if limited to group
|
|
if ( $group && $count > 0 && $render_count > $count ) {
|
|
break;
|
|
}
|
|
|
|
// Data
|
|
$warning = get_post_meta( $chapter_id, 'fictioneer_chapter_warning', true );
|
|
$icon = fictioneer_get_icon_field( 'fictioneer_chapter_icon', $chapter_id );
|
|
$text_icon = get_post_meta( $chapter_id, 'fictioneer_chapter_text_icon', true );
|
|
$prefix = get_post_meta( $chapter_id, 'fictioneer_chapter_prefix', true );
|
|
$title = fictioneer_get_safe_title( $chapter_id, 'shortcode-chapter-list' );
|
|
$has_password = ! empty( $post->post_password );
|
|
$extra_classes = '_shortcode';
|
|
|
|
if ( $warning ) {
|
|
$extra_classes .= ' _warning';
|
|
}
|
|
|
|
if ( $has_password ) {
|
|
$extra_classes .= ' _password';
|
|
}
|
|
|
|
// Start HTML ---> ?>
|
|
<li class="chapter-group__list-item <?php echo $extra_classes; ?>" data-post-id="<?php echo $chapter_id; ?>">
|
|
<?php
|
|
if ( ! $hide_icons ) {
|
|
// Icon hierarchy: password > scheduled > text > normal
|
|
if ( ! $prefer_chapter_icon && $has_password ) {
|
|
$icon = '<i class="fa-solid fa-lock chapter-group__list-item-icon"></i>';
|
|
} elseif ( ! $prefer_chapter_icon && get_post_status( $chapter_id ) === 'future' ) {
|
|
$icon = '<i class="fa-solid fa-calendar-days chapter-group__list-item-icon"></i>';
|
|
} elseif ( $text_icon ) {
|
|
$icon = "<span class='chapter-group__list-item-icon _text text-icon'>{$text_icon}</span>";
|
|
} else {
|
|
$icon = $icon ?: FICTIONEER_DEFAULT_CHAPTER_ICON;
|
|
$icon = "<i class='{$icon} chapter-group__list-item-icon'></i>";
|
|
}
|
|
|
|
echo apply_filters( 'fictioneer_filter_chapter_icon', $icon, $chapter_id, $story_id );
|
|
}
|
|
?>
|
|
|
|
<a
|
|
href="<?php the_permalink( $chapter_id ); ?>"
|
|
class="chapter-group__list-item-link truncate _1-1 <?php echo $has_password ? '_password' : ''; ?>"
|
|
><?php
|
|
|
|
$title_output = '';
|
|
$prefix = apply_filters( 'fictioneer_filter_list_chapter_prefix', $prefix, $chapter_id, 'shortcode' );
|
|
|
|
if ( ! empty( $prefix ) ) {
|
|
// Mind space between prefix and title
|
|
$title_output .= $prefix . ' ';
|
|
}
|
|
|
|
$title_output .= $title;
|
|
|
|
echo apply_filters(
|
|
'fictioneer_filter_list_chapter_title_row',
|
|
$title_output, $chapter_id, $prefix, $has_password, 'shortcode'
|
|
);
|
|
|
|
?></a>
|
|
|
|
<?php
|
|
// Chapter subrow
|
|
echo fictioneer_get_list_chapter_meta_row(
|
|
array(
|
|
'id' => $chapter_id,
|
|
'warning' => $warning,
|
|
'password' => $has_password,
|
|
'timestamp' => get_the_time( 'c' ),
|
|
'list_date' => get_the_date( '' ),
|
|
'words' => fictioneer_get_word_count( $chapter_id ),
|
|
)
|
|
);
|
|
?>
|
|
|
|
<?php if ( $can_checkmarks && ! empty( $chapter_story_id ) && get_post_status( $chapter_story_id ) === 'publish' ) : ?>
|
|
<button
|
|
class="checkmark chapter-group__list-item-checkmark only-logged-in"
|
|
data-fictioneer-checkmarks-target="chapterCheck"
|
|
data-fictioneer-checkmarks-story-param="<?php echo $chapter_story_id; ?>"
|
|
data-fictioneer-checkmarks-chapter-param="<?php echo $chapter_id; ?>"
|
|
data-action="click->fictioneer-checkmarks#toggleChapter"
|
|
role="checkbox"
|
|
aria-checked="false"
|
|
aria-label="<?php
|
|
printf(
|
|
esc_attr__( 'Chapter checkmark for %s.', 'fictioneer' ),
|
|
esc_attr( wp_strip_all_tags( $title ) )
|
|
);
|
|
?>"
|
|
><i class="fa-solid fa-check"></i></button>
|
|
<?php endif; ?>
|
|
</li>
|
|
<?php // <--- End HTML
|
|
}
|
|
|
|
// Restore postdata
|
|
wp_reset_postdata();
|
|
?>
|
|
</ol>
|
|
</div>
|
|
<?php // <--- End HTML
|
|
|
|
// Store buffer
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( $transient_enabled && $cache ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_chapter_list', 'fictioneer_shortcode_chapter_list' );
|
|
|
|
// =============================================================================
|
|
// CONTACT FORM SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show a contact form
|
|
*
|
|
* @since 5.0.0
|
|
*
|
|
* @param string|null $attr['title'] Optional. Title of the form.
|
|
* @param string|null $attr['submit'] Optional. Submit button caption.
|
|
* @param string|null $attr['privacy_policy'] Optional. Must accept privacy policy.
|
|
* @param string|null $attr['required'] Optional. Make all fields required
|
|
* @param string|null $attr['email'] Optional. Email field.
|
|
* @param string|null $attr['name'] Optional. Name field.
|
|
* @param string|null $attr["text_{$i}"] Optional. Up to 6 extra text field(s).
|
|
* @param string|null $attr["check_{$i}"] Optional. Up to 6 extra checkbox field(s).
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_contact_form( $attr ) {
|
|
// Sanitize attributes
|
|
$attr = is_array( $attr ) ? array_map( 'sanitize_text_field', $attr ) : sanitize_text_field( $attr );
|
|
|
|
// Setup
|
|
$title = $attr['title'] ?? _x( 'Nameless Form', 'Contact form.', 'fictioneer' );
|
|
$submit = $attr['submit'] ?? __( 'Submit', 'fictioneer' );
|
|
$privacy_policy = filter_var( $attr['privacy_policy'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
$required = isset( $attr['required'] ) ? 'required' : '';
|
|
$email = $attr['email'] ?? '';
|
|
$name = $attr['name'] ?? '';
|
|
$classes = wp_strip_all_tags( $attr['class'] ?? '' );
|
|
$fields = [];
|
|
|
|
// HTML snippets
|
|
if ( ! empty( $email ) ) {
|
|
$fields[] = "<input style='opacity: 0;' type='email' name='email' maxlength='100' placeholder='{$email}' {$required}>";
|
|
}
|
|
|
|
if ( ! empty( $name ) ) {
|
|
$fields[] = "<input style='opacity: 0;' type='text' name='name' maxlength='100' placeholder='{$name}' {$required}>";
|
|
}
|
|
|
|
// Custom text fields
|
|
for ( $i = 1; $i <= 6; $i++ ) {
|
|
$field = $attr["text_{$i}"] ?? '';
|
|
|
|
if ( ! empty( $field ) ) {
|
|
$fields[] = "<input style='opacity: 0;' type='text' name='text_{$i}' maxlength='100' placeholder='{$field}' {$required}><input type='hidden' name='text_label_{$i}' value='{$field}'>";
|
|
}
|
|
}
|
|
|
|
// Custom checkboxes
|
|
for ( $i = 1; $i <= 6; $i++ ) {
|
|
$field = $attr["check_{$i}"] ?? '';
|
|
|
|
if ( ! empty( $field ) ) {
|
|
$fields[] = "<label class='checkbox-label'><input class='_no-stretch' style='opacity: 0;' type='checkbox' value='1' name='check_{$i}' autocomplete='off' {$required}><span>{$field}</span></label><input type='hidden' name='check_label_{$i}' value='{$field}'>";
|
|
}
|
|
}
|
|
|
|
// Privacy policy checkbox
|
|
$privacy_policy_link = get_option( 'wp_page_for_privacy_policy' ) ? esc_url( get_privacy_policy_url() ) : false;
|
|
|
|
if ( $privacy_policy && $privacy_policy_link ) {
|
|
$fields[] = "<label class='checkbox-label'><input class='_no-stretch' style='opacity: 0;' type='checkbox' value='1' name='privacy_policy' autocomplete='off' required><span>" . sprintf( fcntr( 'accept_privacy_policy' ), $privacy_policy_link ) . "</span></label><input type='hidden' name='require_privacy_policy' value='1'>";
|
|
}
|
|
|
|
// Apply filters
|
|
$fields = apply_filters( 'fictioneer_filter_contact_form_fields', $fields, get_the_ID() );
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
/*
|
|
* The inline "opacity: 0" style is a reverse bot trap. They are made visible again with CSS,
|
|
* but dumb bots might think this is a trap for them and ignore the fields. Not a reliable
|
|
* spam protection, but this is security in depth.
|
|
*
|
|
* The "phone" and "terms" inputs are honeypots.
|
|
*/
|
|
|
|
// Start HTML ---> ?>
|
|
<form class="fcn-contact-form <?php echo esc_attr( $classes ); ?>">
|
|
<div class="fcn-contact-form__message">
|
|
<textarea class="fcn-contact-form__textarea adaptive-textarea" style="opacity: 0;" name="message" maxlength="65525" placeholder="<?php _e( 'Please enter your message.', 'fictioneer' ); ?>" required></textarea>
|
|
</div>
|
|
<?php if ( ! empty( $fields ) ) : ?>
|
|
<div class="fcn-contact-form__fields">
|
|
<?php foreach ( $fields as $field ) : ?>
|
|
<div class="fcn-contact-form__field"><?php echo $field; ?></div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<input type="checkbox" name="terms" value="1" autocomplete="off" tabindex="-1">
|
|
<input type="tel" name="phone" autocomplete="off" tabindex="-1">
|
|
<input type="hidden" name="title" value="<?php echo $title; ?>">
|
|
<div class="fcn-contact-form__actions">
|
|
<button class="fcn-contact-form__submit button" type="button" data-enabled="<?php echo esc_attr( $submit ); ?>" data-disabled="<?php esc_attr_e( 'Sending…', 'fictioneer' ); ?>" data-done="<?php esc_attr_e( 'Message sent!', 'fictioneer' ); ?>"><?php echo $submit; ?></button>
|
|
</div>
|
|
</form>
|
|
<?php // <--- End HTML
|
|
|
|
// Return minified buffer
|
|
return fictioneer_minify_html( ob_get_clean() );
|
|
}
|
|
add_shortcode( 'fictioneer_contact_form', 'fictioneer_shortcode_contact_form' );
|
|
|
|
// =============================================================================
|
|
// SEARCH SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show the latest post
|
|
*
|
|
* @since 5.0.0
|
|
*
|
|
* @param string|null $attr['simple'] Optional. Hide the advanced options.
|
|
* @param string|null $attr['placeholder'] Optional. Placeholder text.
|
|
* @param string|null $attr['type'] Optional. Default post type to query.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_search( $attr ) {
|
|
// Sanitize attributes
|
|
$attr = is_array( $attr ) ? array_map( 'sanitize_text_field', $attr ) : sanitize_text_field( $attr );
|
|
|
|
// Setup
|
|
$args = array( 'cache' => true );
|
|
$simple = isset( $attr['simple'] ) ? $attr['simple'] == 'true' || $attr['simple'] == '1' : false;
|
|
$placeholder = $attr['placeholder'] ?? false;
|
|
$type = $attr['type'] ?? false;
|
|
$pre_tags = fictioneer_explode_list( $attr['tags'] ?? '' );
|
|
$pre_genres = fictioneer_explode_list( $attr['genres'] ?? '' );
|
|
$pre_fandoms = fictioneer_explode_list( $attr['fandoms'] ?? '' );
|
|
$pre_characters = fictioneer_explode_list( $attr['characters'] ?? '' );
|
|
$pre_warnings = fictioneer_explode_list( $attr['warnings'] ?? '' );
|
|
|
|
// Prepare arguments
|
|
$args['expanded'] = filter_var( $attr['expanded'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
|
|
if ( $simple ) {
|
|
$args['simple'] = $simple;
|
|
}
|
|
|
|
if ( $placeholder ) {
|
|
$args['placeholder'] = $placeholder;
|
|
}
|
|
|
|
if ( $type && in_array( $type, ['any', 'story', 'chapter', 'recommendation', 'collection', 'post'] ) ) {
|
|
$args['preselect_type'] = in_array( $type, ['story', 'chapter', 'recommendation', 'collection'] ) ? "fcn_{$type}" : $type;
|
|
}
|
|
|
|
if ( $pre_tags ) {
|
|
$args['preselect_tags'] = array_map( 'absint', $pre_tags );
|
|
}
|
|
|
|
if ( $pre_genres ) {
|
|
$args['preselect_genres'] = array_map( 'absint', $pre_genres );
|
|
}
|
|
|
|
if ( $pre_fandoms ) {
|
|
$args['preselect_fandoms'] = array_map( 'absint', $pre_fandoms );
|
|
}
|
|
|
|
if ( $pre_characters ) {
|
|
$args['preselect_characters'] = array_map( 'absint', $pre_characters );
|
|
}
|
|
|
|
if ( $pre_warnings ) {
|
|
$args['preselect_warnings'] = array_map( 'absint', $pre_warnings );
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
get_search_form( $args );
|
|
|
|
// Return minified buffer
|
|
return fictioneer_minify_html( ob_get_clean() );
|
|
}
|
|
add_shortcode( 'fictioneer_search', 'fictioneer_shortcode_search' );
|
|
|
|
// =============================================================================
|
|
// BLOG SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show blog with pagination
|
|
*
|
|
* @since 5.2.0
|
|
*
|
|
* @param string|null $attr['per_page'] Optional. Number of posts per page.
|
|
* @param string|null $attr['ignore_sticky'] Optional. Whether to ignore sticky posts. Default false.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_blog( $attr ) {
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr );
|
|
|
|
// Query arguments
|
|
$query_args = array(
|
|
'fictioneer_query_name' => 'blog_shortcode',
|
|
'post_type' => 'post',
|
|
'post_status' => $args['post_status'],
|
|
'paged' => $args['page'],
|
|
'posts_per_page' => $args['posts_per_page'],
|
|
'ignore_sticky_posts' => $args['ignore_sticky']
|
|
);
|
|
|
|
// Author?
|
|
if ( ! empty( $args['author'] ) ) {
|
|
$query_args['author_name'] = $args['author'];
|
|
}
|
|
|
|
// Author IDs?
|
|
if ( ! empty( $args['author_ids'] ) ) {
|
|
$query_args['author__in'] = $args['author_ids'];
|
|
}
|
|
|
|
// Taxonomies?
|
|
if ( ! empty( $args['taxonomies'] ) ) {
|
|
$query_args['tax_query'] = fictioneer_get_shortcode_tax_query( $args );
|
|
}
|
|
|
|
// Excluded tags?
|
|
if ( ! empty( $args['excluded_tags'] ) ) {
|
|
$query_args['tag__not_in'] = $args['excluded_tags'];
|
|
}
|
|
|
|
// Excluded categories?
|
|
if ( ! empty( $args['excluded_cats'] ) ) {
|
|
$query_args['category__not_in'] = $args['excluded_cats'];
|
|
}
|
|
|
|
// Excluded authors?
|
|
if ( ! empty( $args['excluded_authors'] ) ) {
|
|
$query_args['author__not_in'] = $args['excluded_authors'];
|
|
}
|
|
|
|
// Exclude protected
|
|
if ( $args['ignore_protected'] ) {
|
|
$query_args['has_password'] = false;
|
|
}
|
|
|
|
// Apply filters
|
|
$query_args = apply_filters( 'fictioneer_filter_shortcode_blog_query_args', $query_args, $args );
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_blog' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $query_args ) . serialize( $args ) . serialize( $attr );
|
|
$transient_key = 'fictioneer_shortcode_blog_html_' . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Query
|
|
$blog_query = new WP_Query( $query_args );
|
|
|
|
// Prime author cache
|
|
if ( function_exists( 'update_post_author_caches' ) ) {
|
|
update_post_author_caches( $blog_query->posts );
|
|
}
|
|
|
|
// Pagination
|
|
$pag_args = array(
|
|
'current' => $args['page'],
|
|
'total' => $blog_query->max_num_pages,
|
|
'prev_text' => fcntr( 'previous' ),
|
|
'next_text' => fcntr( 'next' ),
|
|
'add_fragment' => '#blog'
|
|
);
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
if ( $blog_query->have_posts() ) {
|
|
// Start HTML ---> ?>
|
|
<section id="blog" class="scroll-margin-top blog-posts _nested <?php echo $args['classes']; ?>">
|
|
<?php
|
|
while ( $blog_query->have_posts() ) {
|
|
$blog_query->the_post();
|
|
get_template_part( 'partials/_post', null, array( 'nested' => true, 'context' => 'shortcode_fictioneer_blog' ) );
|
|
}
|
|
|
|
wp_reset_postdata();
|
|
|
|
if ( $blog_query->max_num_pages > 1 ) {
|
|
echo '<nav class="pagination">' . fictioneer_paginate_links( $pag_args ) . '</nav>';
|
|
}
|
|
?>
|
|
</section>
|
|
<?php // <--- End HTML
|
|
} else {
|
|
// Start HTML ---> ?>
|
|
<article class="post _empty">
|
|
<span><?php _e( 'No (more) posts found.', 'fictioneer' ); ?></span>
|
|
</article>
|
|
<?php // <--- End HTML
|
|
}
|
|
|
|
// Store buffer
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_blog', 'fictioneer_shortcode_blog' );
|
|
|
|
// =============================================================================
|
|
// ARTICLE CARDS SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show article cards with pagination
|
|
*
|
|
* @since 5.7.3
|
|
*
|
|
* @param string|null $attr['post_type'] Optional. The post types to query. Default 'post'.
|
|
* @param string|null $attr['post_status'] Optional. Choose a valid post status. Default 'publish'.
|
|
* @param string|null $attr['post_ids'] Optional. Limit posts to specific post IDs.
|
|
* @param string|null $attr['per_page'] Optional. Number of posts per page.
|
|
* @param string|null $attr['count'] Optional. Maximum number of posts. Default -1.
|
|
* @param string|null $attr['order'] Optional. Order argument. Default 'DESC'.
|
|
* @param string|null $attr['orderby'] Optional. Orderby argument. Default 'date'.
|
|
* @param string|null $attr['ignore_sticky'] Optional. Whether to ignore sticky posts. Default false.
|
|
* @param string|null $attr['ignore_protected'] Optional. Whether to ignore protected posts. Default false.
|
|
* @param string|null $attr['only_protected'] Optional. Whether to query only protected posts. Default false.
|
|
* @param string|null $attr['author'] Optional. Limit posts to a specific author.
|
|
* @param string|null $attr['author_ids'] Optional. Only include posts by these author IDs.
|
|
* @param string|null $attr['exclude_author_ids'] Optional. Exclude posts with these author IDs.
|
|
* @param string|null $attr['exclude_tag_ids'] Optional. Exclude posts with these tags.
|
|
* @param string|null $attr['exclude_cat_ids'] Optional. Exclude posts with these categories.
|
|
* @param string|null $attr['categories'] Optional. Limit posts to specific category names.
|
|
* @param string|null $attr['tags'] Optional. Limit posts to specific tag names.
|
|
* @param string|null $attr['fandoms'] Optional. Limit posts to specific fandom names.
|
|
* @param string|null $attr['genres'] Optional. Limit posts to specific genre names.
|
|
* @param string|null $attr['characters'] Optional. Limit posts to specific character names.
|
|
* @param string|null $attr['rel'] Optional. Relationship between taxonomies. Default 'AND'.
|
|
* @param string|null $attr['seamless'] Optional. Whether to render the image seamless. Default false (Customizer).
|
|
* @param string|null $attr['aspect_ratio'] Optional. Aspect ratio for the image.
|
|
* @param string|null $attr['lightbox'] Optional. Whether the thumbnail is opened in the lightbox. Default true.
|
|
* @param string|null $attr['thumbnail'] Optional. Whether to show the thumbnail. Default true (Customizer).
|
|
* @param string|null $attr['date_format'] Optional. String to override the date format. Default empty.
|
|
* @param string|null $attr['footer'] Optional. Whether to show the footer (if any). Default true.
|
|
* @param string|null $attr['footer_author'] Optional. Whether to show the post author. Default true.
|
|
* @param string|null $attr['footer_date'] Optional. Whether to show the post date. Default true.
|
|
* @param string|null $attr['footer_comments'] Optional. Whether to show the post comment count. Default true.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $args['splide'] Configuration JSON for the Splide slider. Default empty.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_article_cards( $attr ) {
|
|
// Defaults
|
|
$args = fictioneer_get_default_shortcode_args( $attr );
|
|
|
|
// Terms
|
|
$args['terms'] = fictioneer_sanitize_query_var( $attr['terms'] ?? 0, ['inline', 'pills', 'none', 'false'], 'inline' );
|
|
$args['max_terms'] = absint( ( $attr['max_terms'] ?? 10 ) ?: 10 );
|
|
|
|
// Post type(s)...
|
|
$post_types = sanitize_text_field( $attr['post_type'] ?? 'post' );
|
|
$post_types = fictioneer_explode_list( $post_types );
|
|
|
|
$allowed_post_types = array(
|
|
'post' => 'post',
|
|
'posts' => 'post',
|
|
'page' => 'page',
|
|
'pages' => 'page',
|
|
'story' => 'fcn_story',
|
|
'stories' => 'fcn_story',
|
|
'chapter' => 'fcn_chapter',
|
|
'chapters' => 'fcn_chapter',
|
|
'collection' => 'fcn_collection',
|
|
'collections' => 'fcn_collection',
|
|
'recommendation' => 'fcn_recommendation',
|
|
'recommendations' => 'fcn_recommendation'
|
|
);
|
|
|
|
// ... must be in array
|
|
$query_post_types = array_map( function( $item ) use ( $allowed_post_types ) {
|
|
return $allowed_post_types[ $item ] ?? null;
|
|
}, $post_types);
|
|
|
|
// ... remove null values
|
|
$query_post_types = array_filter( $query_post_types, function( $value ) {
|
|
return ! is_null( $value );
|
|
});
|
|
|
|
// ... fix array
|
|
$query_post_types = array_unique( $query_post_types );
|
|
$query_post_types = array_values( $query_post_types );
|
|
$query_post_types = empty( $query_post_types ) ? ['post'] : $query_post_types;
|
|
|
|
// ... add to args
|
|
$args['post_type'] = $query_post_types;
|
|
|
|
// Extra classes
|
|
if ( $args['splide'] ?? 0 ) {
|
|
$args['classes'] .= ' splide _splide-placeholder';
|
|
}
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_article_cards' );
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
$base = serialize( $args ) . serialize( $attr );
|
|
$transient_key = "fictioneer_shortcode_article_cards_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
get_template_part( 'partials/_article-cards', null, $args );
|
|
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
if ( ( $args['splide'] ?? 0 ) && strpos( $args['classes'], 'no-auto-splide' ) === false ) {
|
|
$html .= fictioneer_get_splide_inline_init();
|
|
}
|
|
|
|
if ( $transient_enabled && $args['cache'] ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_article_cards', 'fictioneer_shortcode_article_cards' );
|
|
|
|
// =============================================================================
|
|
// STORY SECTION SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show story section
|
|
*
|
|
* @since 5.14.0
|
|
*
|
|
* @param string $attr['story_id'] The ID of the story.
|
|
* @param string|null $attr['tabs'] Optional. Whether to show the tabs above chapters. Default false.
|
|
* @param string|null $attr['blog'] Optional. Whether to show the blog tab. Default false.
|
|
* @param string|null $attr['pages'] Optional. Whether to show the custom page tabs. Default false.
|
|
* @param string|null $attr['scheduled'] Optional. Whether to show the scheduled chapter note. Default false.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_story_section( $attr ) {
|
|
global $post;
|
|
|
|
// Abort if...
|
|
if ( ! is_page_template( 'singular-story.php' ) ) {
|
|
return fictioneer_notice(
|
|
__( 'The [fictioneer_story_section] shortcode requires the "Story Page" template.' ),
|
|
'warning',
|
|
false
|
|
);
|
|
}
|
|
|
|
// Setup
|
|
$cache = filter_var( $attr['cache'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$story_id = fictioneer_validate_id( $attr['story_id'] ?? 0, 'fcn_story' );
|
|
$post = get_post( $story_id );
|
|
$story_data = fictioneer_get_story_data( $story_id );
|
|
$classes = wp_strip_all_tags( $attr['class'] ?? '' );
|
|
$show_tabs = filter_var( $attr['tabs'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
$show_pages = filter_var( $attr['pages'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
$show_blog = filter_var( $attr['blog'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
$show_scheduled = filter_var( $attr['scheduled'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
$hook_args = array( 'story_id' => $story_id, 'story_data' => $story_data, 'password_required' => post_password_required() );
|
|
|
|
// Abort if...
|
|
if ( ! $story_data ) {
|
|
return '';
|
|
}
|
|
|
|
// Prepare classes
|
|
if ( ! get_option( 'fictioneer_enable_checkmarks' ) ) {
|
|
$classes .= ' _no-checkmarks';
|
|
}
|
|
|
|
if ( ! $show_pages || ! $show_tabs ) {
|
|
$classes .= ' _no-pages';
|
|
}
|
|
|
|
if ( ! $show_blog || ! $show_tabs ) {
|
|
$classes .= ' _no-blog';
|
|
}
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_story_section' );
|
|
|
|
if ( $transient_enabled && $cache ) {
|
|
$base = serialize( $attr ) . $classes;
|
|
$transient_key = "fictioneer_shortcode_story_section_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Require functions (necessary in post editor for some reason)
|
|
require_once __DIR__ . '/hooks/_story_hooks.php';
|
|
|
|
// Setup post data
|
|
setup_postdata( $post );
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
echo '<div class="story-section-shortcode story _shortcode ' . esc_attr( $classes ) . '">';
|
|
|
|
if ( $show_tabs ) {
|
|
fictioneer_story_tabs( $hook_args );
|
|
}
|
|
|
|
if ( $show_scheduled ) {
|
|
fictioneer_story_scheduled_chapter( $hook_args );
|
|
}
|
|
|
|
if ( $show_tabs && $show_pages ) {
|
|
fictioneer_story_pages( $hook_args );
|
|
}
|
|
|
|
fictioneer_story_chapters( $hook_args );
|
|
|
|
if ( $show_tabs && $show_blog ) {
|
|
fictioneer_story_blog( $hook_args );
|
|
}
|
|
|
|
echo '</div>';
|
|
|
|
// Store buffer
|
|
$html = fictioneer_minify_html( ob_get_clean() );
|
|
|
|
// Reset post data
|
|
wp_reset_postdata();
|
|
|
|
// Cache in Transient
|
|
if ( $transient_enabled && $cache ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified buffer
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_story_section', 'fictioneer_shortcode_story_section' );
|
|
|
|
// =============================================================================
|
|
// STORY ACTIONS SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show story actions
|
|
*
|
|
* @since 5.14.0
|
|
*
|
|
* @param string $attr['story_id'] The ID of the story.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $attr['follow'] Optional. Whether to show the Follow button if enabled. Default true.
|
|
* @param string|null $attr['reminder'] Optional. Whether to show the Reminder button if enabled. Default true.
|
|
* @param string|null $attr['subscribe'] Optional. Whether to show the Subscribe button if enabled. Default true.
|
|
* @param string|null $attr['download'] Optional. Whether to show the Download button if enabled. Default true.
|
|
* @param string|null $attr['rss'] Optional. Whether to show the RSS links if enabled. Default true.
|
|
* @param string|null $attr['share'] Optional. Whether to show the Share buttons if enabled. Default true.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_story_actions( $attr ) {
|
|
// Abort if...
|
|
if ( ! is_page_template( 'singular-story.php' ) ) {
|
|
return fictioneer_notice(
|
|
__( 'The [fictioneer_story_actions] shortcode requires the "Story Page" template.' ),
|
|
'warning',
|
|
false
|
|
);
|
|
}
|
|
|
|
// Setup
|
|
$cache = filter_var( $attr['cache'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$story_id = fictioneer_validate_id( $attr['story_id'] ?? 0, 'fcn_story' );
|
|
$story_data = fictioneer_get_story_data( $story_id );
|
|
$classes = wp_strip_all_tags( $attr['class'] ?? '' );
|
|
$follow = filter_var( $attr['follow'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$reminder = filter_var( $attr['reminder'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$subscribe = filter_var( $attr['subscribe'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$download = filter_var( $attr['download'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$rss = filter_var( $attr['rss'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$share = filter_var( $attr['share'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
|
|
// Abort if...
|
|
if ( ! $story_data ) {
|
|
return '';
|
|
}
|
|
|
|
// Prepare hook arguments
|
|
$hook_args = array(
|
|
'post_id' => $story_id,
|
|
'post_type' => 'fcn_story',
|
|
'story_id' => $story_id,
|
|
'story_data' => $story_data,
|
|
'follow' => $follow,
|
|
'reminder' => $reminder,
|
|
'subscribe' => $subscribe,
|
|
'download' => $download,
|
|
'rss' => $rss,
|
|
'share' => $share
|
|
);
|
|
|
|
// Transient?
|
|
$transient_enabled = fictioneer_enable_shortcode_transients( 'fictioneer_story_actions' );
|
|
|
|
if ( $transient_enabled && $cache ) {
|
|
$base = serialize( $attr ) . $classes;
|
|
$transient_key = "fictioneer_shortcode_story_actions_html_" . md5( $base );
|
|
$transient = get_transient( $transient_key );
|
|
|
|
if ( ! empty( $transient ) ) {
|
|
return $transient;
|
|
}
|
|
}
|
|
|
|
// Add filter for buttons
|
|
add_filter( 'fictioneer_filter_story_buttons', 'fictioneer_shortcode_remove_story_buttons', 99, 2 );
|
|
|
|
// Build HTML
|
|
$html = '<section class="story-actions story__after-summary ' . esc_attr( $classes ) . '">';
|
|
$html .= fictioneer_get_media_buttons( $hook_args );
|
|
$html .= '<div class="story__actions">' . fictioneer_get_story_buttons( $hook_args ) . '</div></section>';
|
|
|
|
// Remove filter for buttons
|
|
remove_filter( 'fictioneer_shortcode_remove_story_buttons', 99, 2 );
|
|
|
|
// Minify HTML
|
|
$html = fictioneer_minify_html( $html );
|
|
|
|
// Cache in Transient
|
|
if ( $transient_enabled && $cache ) {
|
|
set_transient( $transient_key, $html, FICTIONEER_SHORTCODE_TRANSIENT_EXPIRATION );
|
|
}
|
|
|
|
// Return minified HTML
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fictioneer_story_actions', 'fictioneer_shortcode_story_actions' );
|
|
|
|
/**
|
|
* Removes buttons for the [fictioneer_story_actions] shortcode
|
|
*
|
|
* This function only works if boolean arguments are provided for
|
|
* 'follow', 'reminder', 'subscribe', and/or 'download'.
|
|
*
|
|
* @since 5.14.0
|
|
*
|
|
* @param array $output Associative array with HTML for buttons to be rendered.
|
|
* @param array $args Arguments passed to filter.
|
|
*
|
|
* @return array The filtered output.
|
|
*/
|
|
|
|
function fictioneer_shortcode_remove_story_buttons( $output, $args ) {
|
|
if ( ! ( $args['follow'] ?? 1 ) ) {
|
|
unset( $output['follow'] );
|
|
}
|
|
|
|
if ( ! ( $args['reminder'] ?? 1 ) ) {
|
|
unset( $output['reminder'] );
|
|
}
|
|
|
|
if ( ! ( $args['subscribe'] ?? 1 ) ) {
|
|
unset( $output['subscribe'] );
|
|
}
|
|
|
|
if ( ! ( $args['download'] ?? 1 ) ) {
|
|
unset( $output['epub'] );
|
|
unset( $output['ebook'] );
|
|
}
|
|
|
|
return $output;
|
|
};
|
|
|
|
// =============================================================================
|
|
// SUBSCRIBE BUTTON SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show subscribe button
|
|
*
|
|
* @since 5.14.0
|
|
*
|
|
* @param string|null $attr['post_id'] Optional. Post ID to subscribe to (for plugins). Defaults to current ID.
|
|
* @param string|null $attr['story_id'] Optional. Story ID to subscribe to (for plugins). Defaults to current ID.
|
|
* @param string|null $attr['inline'] Optional. Whether the button should be wrapped in a block. Default true.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_subscribe_button( $attr ) {
|
|
// Setup
|
|
$post_id = absint( $attr['post_id'] ?? $attr['story_id'] ?? get_the_ID() );
|
|
$classes = wp_strip_all_tags( $attr['class'] ?? '' );
|
|
$subscribe_buttons = fictioneer_get_subscribe_options( $post_id );
|
|
|
|
if ( filter_var( $attr['inline'] ?? 0, FILTER_VALIDATE_BOOLEAN ) ) {
|
|
$classes .= ' _inline';
|
|
}
|
|
|
|
// Build and return button
|
|
if ( ! empty( $subscribe_buttons ) ) {
|
|
return sprintf(
|
|
'<div class="subscribe-menu-toggle button _secondary popup-menu-toggle _popup-right-if-last ' . esc_attr( $classes ) . '" tabindex="0" role="button" aria-label="%s" data-fictioneer-last-click-target="toggle" data-action="click->fictioneer-last-click#toggle"><div><i class="fa-solid fa-bell"></i> %s</div><div class="popup-menu _bottom _center">%s</div></div>',
|
|
fcntr( 'subscribe', true ),
|
|
fcntr( 'subscribe' ),
|
|
$subscribe_buttons
|
|
);
|
|
}
|
|
|
|
// Return nothing if empty
|
|
return '';
|
|
}
|
|
add_shortcode( 'fictioneer_subscribe_button', 'fictioneer_shortcode_subscribe_button' );
|
|
|
|
// =============================================================================
|
|
// STORY COMMENTS SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show story comments
|
|
*
|
|
* @since 5.14.0
|
|
*
|
|
* @param string|null $attr['story_id'] Optional. Story ID to get comments for. Defaults to current ID.
|
|
* @param string|null $attr['header'] Optional. Whether to show the heading with count. Default true.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_story_comments( $attr ) {
|
|
// Abort if...
|
|
if ( ! is_page_template( 'singular-story.php' ) ) {
|
|
return fictioneer_notice(
|
|
__( 'The [fictioneer_story_comments] shortcode requires the "Story Page" template.' ),
|
|
'warning',
|
|
false
|
|
);
|
|
}
|
|
|
|
// Setup
|
|
$story_id = fictioneer_validate_id( $attr['story_id'] ?? get_the_ID(), 'fcn_story' );
|
|
$story_data = fictioneer_get_story_data( $story_id ?: 0 );
|
|
$header = filter_var( $attr['header'] ?? 1, FILTER_VALIDATE_BOOLEAN );
|
|
$classes = wp_strip_all_tags( $attr['classes'] ?? $attr['class'] ?? '' );
|
|
$style = esc_attr( wp_strip_all_tags( $attr['style'] ?? '' ) );
|
|
|
|
if ( ! $story_data ) {
|
|
return '';
|
|
}
|
|
|
|
// Require functions (necessary in post editor for some reason)
|
|
require_once __DIR__ . '/hooks/_story_hooks.php';
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
// Output story comment section
|
|
fictioneer_story_comments(
|
|
array(
|
|
'story_id' => $story_id,
|
|
'story_data' => $story_data,
|
|
'shortcode' => 1,
|
|
'classes' => $classes,
|
|
'header' => $header,
|
|
'style' => $style
|
|
)
|
|
);
|
|
|
|
// Capture and return buffer
|
|
return fictioneer_minify_html( ob_get_clean() );
|
|
}
|
|
add_shortcode( 'fictioneer_story_comments', 'fictioneer_shortcode_story_comments' );
|
|
|
|
// =============================================================================
|
|
// STORY DATA SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show selected story data
|
|
*
|
|
* Data: id, word_count, chapter_count, icon, age_rating, rating_letter, comment_count,
|
|
* datetime, date, time, categories, tags, genres, fandoms, characters, or warnings.
|
|
*
|
|
* Format: default, raw, or short. Not all of them apply to all data.
|
|
*
|
|
* @since 5.14.0
|
|
*
|
|
* @param string|null $attr['data'] The requested data, one at a time. See description.
|
|
* @param string|null $attr['story_id'] Optional. Story ID to get comments for. Defaults to current ID.
|
|
* @param string|null $attr['format'] Optional. Special formatting for selected data. See description.
|
|
* @param string|null $attr['date_format'] Optional. Format for date string. Defaults to WP settings.
|
|
* @param string|null $attr['time_format'] Optional. Format for time string. Defaults to WP settings.
|
|
* @param string|null $attr['separator'] Optional. Separator string for tags, genres, fandoms, etc.
|
|
* @param string|null $attr['tag'] Optional. The wrapper HTML tag. Defaults to 'span'.
|
|
* @param string|null $attr['class'] Optional. Additional CSS classes, separated by whitespace.
|
|
* @param string|null $attr['inner_class'] Optional. Additional CSS classes for nested items, separated by whitespace.
|
|
* @param string|null $attr['style'] Optional. Inline style applied to wrapper element.
|
|
* @param string|null $attr['inner_style'] Optional. Inline style applied to nested items.
|
|
*
|
|
* @return string The shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_story_data( $attr ) {
|
|
// Setup
|
|
$story_id = fictioneer_validate_id( $attr['story_id'] ?? get_the_ID(), 'fcn_story' );
|
|
$story_data = fictioneer_get_story_data( $story_id ?: 0 );
|
|
$data = $attr['data'] ?? '';
|
|
$format = $attr['format'] ?? '';
|
|
$separator = wp_strip_all_tags( $attr['separator'] ?? '' ) ?: ', ';
|
|
$classes = esc_attr( wp_strip_all_tags( $attr['class'] ?? '' ) );
|
|
$inner_classes = esc_attr( wp_strip_all_tags( $attr['inner_class'] ?? '' ) );
|
|
$style = esc_attr( wp_strip_all_tags( $attr['style'] ?? '' ) );
|
|
$inner_style = esc_attr( wp_strip_all_tags( $attr['inner_style'] ?? '' ) );
|
|
$tag = wp_strip_all_tags( $attr['tag'] ?? 'span' );
|
|
$output = '';
|
|
|
|
if ( ! $story_data ) {
|
|
return '';
|
|
}
|
|
|
|
// Get requested data
|
|
switch ( $data ) {
|
|
case 'word_count':
|
|
$output = $story_data['word_count'] ?? 0;
|
|
$output = $format !== 'short' ? $output : fictioneer_shorten_number( $output );
|
|
$output = ( $format === 'raw' || $format === 'short' ) ? $output : number_format_i18n( $output );
|
|
break;
|
|
case 'chapter_count':
|
|
$output = $story_data['chapter_count'] ?? 0;
|
|
$output = $format === 'raw' ? $output : number_format_i18n( $output );
|
|
break;
|
|
case 'status':
|
|
$output = $story_data['status'] ?? '';
|
|
break;
|
|
case 'icon':
|
|
$output = esc_attr( $story_data['icon'] ?? '' );
|
|
$output = $output ? "<i class='{$output}'></i>" : '';
|
|
break;
|
|
case 'age_rating':
|
|
$output = $story_data['rating'] ?? '';
|
|
break;
|
|
case 'rating_letter':
|
|
$output = $story_data['rating_letter'] ?? '';
|
|
break;
|
|
case 'comment_count':
|
|
$output = $story_data['comment_count'] ?? 0;
|
|
$output = $format === 'raw' ? $output : number_format_i18n( $output );
|
|
break;
|
|
case 'id':
|
|
$output = $story_data['id'] ?? '';
|
|
break;
|
|
case 'datetime':
|
|
$date = get_the_date( $attr['date_format'] ?? '', $story_id );
|
|
$time = get_the_time( $attr['time_format'] ?? '', $story_id );
|
|
$output = sprintf( $format ? $format : '%s at %s', $date, $time );
|
|
break;
|
|
case 'date':
|
|
$output = get_the_date( $attr['date_format'] ?? '', $story_id );
|
|
break;
|
|
case 'time':
|
|
$output = get_the_time( $attr['time_format'] ?? '', $story_id );
|
|
break;
|
|
}
|
|
|
|
// Get requested terms
|
|
if ( in_array( $data, ['categories', 'tags', 'genres', 'fandoms', 'characters', 'warnings'] ) ) {
|
|
$terms = $data === 'categories' ? get_the_category( $story_id ) : ( $story_data[ $data ] ?? [] );
|
|
$terms = is_array( $terms ) ? $terms : [];
|
|
$output = [];
|
|
|
|
foreach ( $terms as $term ) {
|
|
$link = get_tag_link( $term );
|
|
$output[] = "<a href='{$link}' class='story-page-terms _{$data} {$inner_classes}' style='{$inner_style}'>{$term->name}</a>";
|
|
}
|
|
|
|
$output = implode( $separator, $output );
|
|
}
|
|
|
|
// Build and return output
|
|
return $output ? "<{$tag} class='story-data {$classes}' style='{$style}'>{$output}</{$tag}>" : '';
|
|
}
|
|
add_shortcode( 'fictioneer_story_data', 'fictioneer_shortcode_story_data' );
|
|
|
|
// =============================================================================
|
|
// FONT AWESOME SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show a Font Awesome icon
|
|
*
|
|
* @since 5.14.0
|
|
*
|
|
* @param string|null $attr['class'] The icon classes, separated by whitespace.
|
|
*
|
|
* @return string The shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_font_awesome( $attr ) {
|
|
// Setup
|
|
$classes = esc_attr( trim( wp_strip_all_tags( $attr['class'] ?? '' ) ) );
|
|
|
|
if ( empty( $classes ) ) {
|
|
return '';
|
|
}
|
|
|
|
// Build and return output
|
|
return "<i class='{$classes}'></i>";
|
|
}
|
|
add_shortcode( 'fictioneer_fa', 'fictioneer_shortcode_font_awesome' );
|
|
|
|
// =============================================================================
|
|
// SIDEBAR SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show sidebar
|
|
*
|
|
* @since 5.20.0
|
|
*
|
|
* @param string|null $attr['name'] Optional. Name of the sidebar. Default 'fictioneer_sidebar'.
|
|
*
|
|
* @return string The captured shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_sidebar( $attr ) {
|
|
// Setup
|
|
$name = sanitize_text_field( $attr['name'] ?? '' ) ?: 'fictioneer-sidebar';
|
|
|
|
// Buffer
|
|
ob_start();
|
|
|
|
// Does sidebar exist?
|
|
if ( ! is_active_sidebar( $name ) ) {
|
|
return;
|
|
}
|
|
|
|
// Remove filters
|
|
remove_filter( 'excerpt_more', 'fictioneer_excerpt_ellipsis' );
|
|
remove_filter( 'excerpt_length', 'fictioneer_custom_excerpt_length' );
|
|
|
|
// Start HTML ---> ?>
|
|
<div class="fictioneer-sidebar _shortcode">
|
|
<div class="fictioneer-sidebar__wrapper">
|
|
<?php dynamic_sidebar( $name ); ?>
|
|
</div>
|
|
</div>
|
|
<?php // <--- End HTML
|
|
|
|
// Restore filters
|
|
add_filter( 'excerpt_more', 'fictioneer_excerpt_ellipsis' );
|
|
add_filter( 'excerpt_length', 'fictioneer_custom_excerpt_length' );
|
|
|
|
// Capture and return buffer
|
|
return ob_get_clean();
|
|
}
|
|
|
|
if ( ! get_option( 'fictioneer_disable_all_widgets' ) ) {
|
|
add_shortcode( 'fictioneer_sidebar', 'fictioneer_shortcode_sidebar' );
|
|
}
|
|
|
|
// =============================================================================
|
|
// TOOLTIP AND FOOTNOTE SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to add a tooltip with an associated footnote
|
|
*
|
|
* @since 5.25.0
|
|
*
|
|
* @param string $atts['header'] Optional. Header of the tooltip.
|
|
* @param string $atts['content'] Content of the tooltip.
|
|
* @param bool $atts['footnote'] Optional. Whether to show the footnote. Default true.
|
|
* @param string $content Shortcode content.
|
|
*
|
|
* @return string HTML for the tooltip and associated footnote link.
|
|
*/
|
|
|
|
function fictioneer_shortcode_tooltip( $atts, $content = null ) {
|
|
// Initialize a static counter for unique tooltip/footnote IDs
|
|
static $tooltip_id_counter = 0;
|
|
|
|
// Setup
|
|
$default_atts = array(
|
|
'header' => '',
|
|
'content' => '',
|
|
'footnote' => true,
|
|
);
|
|
|
|
$atts = shortcode_atts( $default_atts, $atts, 'fcnt' );
|
|
$footnote_allowed = get_option( 'fictioneer_generate_footnotes_from_tooltips' ) && $atts['footnote'];
|
|
$footnote_link = '';
|
|
|
|
// Sanitize user inputs
|
|
$tooltip_header = trim( wp_kses_post( $atts[ 'header' ] ) );
|
|
$tooltip_content = trim( wp_kses_post( $atts[ 'content' ] ) );
|
|
|
|
// Bail if no content
|
|
if ( empty( $tooltip_content ) ) {
|
|
return $content;
|
|
}
|
|
|
|
// Increment counter
|
|
$tooltip_id_counter++;
|
|
|
|
// Prepare footnote if allowed
|
|
if ( $footnote_allowed ) {
|
|
// Create a footnote link to be appended to the tooltip content
|
|
$footnote_link = sprintf(
|
|
'<sup class="tooltip-counter"><a href="#footnote-%1$d" class="footnote-link">%1$d</a></sup>',
|
|
$tooltip_id_counter
|
|
);
|
|
}
|
|
|
|
// Prepare data attributes for the tooltip
|
|
$tooltip_data = array(
|
|
'dialog-header' => $tooltip_header,
|
|
'dialog-content' => $tooltip_content . $footnote_link,
|
|
);
|
|
|
|
// Convert data array to HTML attributes
|
|
$tooltip_data_attributes = array_map(
|
|
function ( $key, $value ) {
|
|
return sprintf( 'data-%s="%s"', esc_attr( $key ), esc_attr( $value ) );
|
|
},
|
|
array_keys( $tooltip_data ),
|
|
$tooltip_data
|
|
);
|
|
|
|
$tooltip_title = _x( 'Click to see note', 'Tooltip shortcode.', 'fictioneer' );
|
|
|
|
// Construct the HTML for the tooltip
|
|
$html = sprintf(
|
|
'<span><a id="tooltip-%1$d" class="modal-tooltip" title="%2$s" %3$s data-click-action="open-tooltip-modal">%4$s</a>%5$s</span>',
|
|
$tooltip_id_counter,
|
|
esc_attr( $tooltip_title ),
|
|
implode( ' ', $tooltip_data_attributes ),
|
|
$content,
|
|
$footnote_link
|
|
);
|
|
|
|
// Collect footnote if allowed
|
|
if ( $footnote_allowed ) {
|
|
do_action( 'fictioneer_collect_footnote', $tooltip_id_counter, $tooltip_content );
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
add_shortcode( 'fcnt', 'fictioneer_shortcode_tooltip' );
|
|
|
|
// =============================================================================
|
|
// TERMS SHORTCODE
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Shortcode to show taxonomies.
|
|
*
|
|
* @since 5.27.2
|
|
*
|
|
* @param string|null $attr['term_type'] Term type. Default 'post_tag'.
|
|
* @param int|null $attr['post_id'] Post ID. Default 0.
|
|
* @param int|null $attr['count'] Maximum number of terms. Default -1 (all).
|
|
* @param string|null $attr['orderby'] Orderby argument. Default 'count'.
|
|
* @param string|null $attr['order'] Order argument. Default 'DESC'.
|
|
* @param bool|null $attr['show_empty'] Whether to show empty terms. Default false.
|
|
* @param bool|null $attr['show_count'] Whether to show term counts. Default false.
|
|
* @param string|null $attr['classes'] Additional section CSS classes. Default empty.
|
|
* @param string|null $attr['inner_classes'] Additional term CSS classes. Default empty.
|
|
* @param string|null $attr['style'] Inline section CSS style. Default empty.
|
|
* @param string|null $attr['inner_style'] Inline term CSS style. Default empty.
|
|
* @param string|null $attr['empty'] Override message for empty query result.
|
|
*
|
|
* @return string The shortcode HTML.
|
|
*/
|
|
|
|
function fictioneer_shortcode_terms( $attr ) {
|
|
// Setup
|
|
$type = sanitize_key( $attr['type'] ?? 'tag' );
|
|
$post_id = absint( $attr['post_id'] ?? 0 );
|
|
$count = max( -1, intval( $attr['count'] ?? -1 ) );
|
|
$orderby = sanitize_text_field( $attr['orderby'] ?? 'count' );
|
|
$order = sanitize_text_field( $attr['order'] ?? 'DESC' );
|
|
$show_empty = filter_var( $attr['show_empty'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
$show_count = filter_var( $attr['show_count'] ?? 0, FILTER_VALIDATE_BOOLEAN );
|
|
$classes = esc_attr( wp_strip_all_tags( $attr['classes'] ?? $attr['class'] ?? '' ) );
|
|
$inner_classes = esc_attr( wp_strip_all_tags( $attr['inner_classes'] ?? $attr['inner_class'] ?? '' ) );
|
|
$style = esc_attr( wp_strip_all_tags( $attr['style'] ?? '' ) );
|
|
$inner_style = esc_attr( wp_strip_all_tags( $attr['inner_style'] ?? '' ) );
|
|
$empty = sanitize_text_field( $attr['empty'] ?? __( 'No taxonomies specified yet.', 'fictioneer' ) );
|
|
|
|
$term_map = array(
|
|
'tag' => 'post_tag',
|
|
'genre' => 'fcn_genre',
|
|
'fandom' => 'fcn_fandom',
|
|
'character' => 'fcn_character',
|
|
'warning' => 'fcn_content_warning'
|
|
);
|
|
|
|
$term_type = $term_map[ $type ] ?? $type;
|
|
|
|
// Term exists?
|
|
if ( ! taxonomy_exists( $term_type ) ) {
|
|
return 'Error: Taxonomy does not exist.';
|
|
}
|
|
|
|
// Post exists?
|
|
if ( $post_id && ! get_post( $post_id ) ) {
|
|
return 'Error: Post not found.';
|
|
}
|
|
|
|
// Prepare query args
|
|
$args = array(
|
|
'fictioneer_query_name' => 'terms_shortcode',
|
|
'taxonomy' => $term_type,
|
|
'orderby' => $orderby,
|
|
'order' => $order,
|
|
'hide_empty' => ! $show_empty
|
|
);
|
|
|
|
if ( $count > 0 ) {
|
|
$args['number'] = $count;
|
|
}
|
|
|
|
// Apply filters
|
|
$args = apply_filters( 'fictioneer_filter_shortcode_terms_query_args', $args, $attr );
|
|
|
|
// Query terms
|
|
if ( $post_id ) {
|
|
$terms = wp_get_post_terms( $post_id, $term_type, $args );
|
|
} else {
|
|
$terms = get_terms( $args );
|
|
}
|
|
|
|
// All good?
|
|
if ( is_wp_error( $terms ) ) {
|
|
return 'Error: ' . $terms->get_error_message();
|
|
}
|
|
|
|
// Build and return HTML
|
|
$html = '';
|
|
|
|
if ( ! empty( $terms ) ) {
|
|
foreach ( $terms as $term ) {
|
|
$html .= sprintf(
|
|
'<a href="%s" class="tag-pill _taxonomy-%s _taxonomy-slug-%s %s" style="%s">%s</a>',
|
|
get_tag_link( $term ),
|
|
str_replace( 'fcn_', '', $term->taxonomy ),
|
|
$term->slug,
|
|
'tag-pill ' . $inner_classes,
|
|
$inner_style,
|
|
$show_count
|
|
? sprintf( _x( '%1$s (%2$s)', 'Terms shortcode with count.', 'fictioneer' ), $term->name, $term->count )
|
|
: $term->name
|
|
);
|
|
}
|
|
} else {
|
|
$html = $empty;
|
|
}
|
|
|
|
return sprintf(
|
|
'<section class="terms-shortcode tag-group %s" style="%s">%s</section>',
|
|
"_{$term_type} {$classes} " . wp_unique_id( 'shortcode-id-' ),
|
|
$style,
|
|
$html
|
|
);
|
|
}
|
|
add_shortcode( 'fictioneer_terms', 'fictioneer_shortcode_terms' );
|