File: /var/www/vhosts/ensaco.es/httpdocs/wp-content/plugins/bb-theme-builder/modules/loop/loop.php
<?php
/**
* @class FLLoopModule
*/
class FLLoopModule extends FLBuilderModule {
/**
* @since 1.5
* @return void
*/
public function __construct() {
parent::__construct(
array(
'name' => __( 'Loop', 'bb-theme-builder' ),
'description' => __( 'A module for building post loops.', 'bb-theme-builder' ),
'category' => __( 'Posts', 'bb-theme-builder' ),
'icon' => 'schedule.svg',
'partial_refresh' => true,
'include_wrapper' => false,
'accepts' => 'all',
'enabled' => class_exists( 'FLBuilderModuleDataRepeater' ),
)
);
FLBuilderAJAX::add_action( 'fl_loop_get_terms', __CLASS__ . '::get_term_options' );
add_filter( 'fl_builder_render_css', __CLASS__ . '::render_connected_css_for_loops', 10, 2 );
}
/**
* Ensure backwards compatibility with old settings.
*
* @since 1.5
* @param object $settings A module settings object.
* @param object $helper A settings compatibility helper.
* @return object
*/
public function filter_settings( $settings, $helper ) {
if ( isset( $settings->term_parent ) && ! isset( $settings->select_terms ) && 0 != $settings->term_parent ) {
$settings->select_terms = 'child';
}
return $settings;
}
/**
* Enqueues scripts for loop module.
*
* @since 1.5
* @return void
*/
public function enqueue_scripts() {
if ( $this->settings && 'scroll' === $this->settings->pagination ) {
$this->add_js( 'jquery-infinitescroll' );
}
}
/**
* Render each item for the loop module.
*
* @since 1.5
* @return void
*/
public function render_item() {
ob_start();
$this->render_children_with_wrapper( 'li', [
'class' => [
'fl-loop-item',
],
] );
// Do shortcodes here so they are parsed in context of the current post.
echo do_shortcode( ob_get_clean() );
}
/**
* Static filter callback for rendering CSS for loop modules in the
* context of the WordPress loop. This allows field connections
* and shortcodes to output the correct values based on the current
* post in the loop.
*
* @since 1.5
* @param string $css
* @param array $nodes
* @return string
*/
static public function render_connected_css_for_loops( $css, $nodes ) {
$loops = [];
foreach ( $nodes['modules'] as $node ) {
if ( isset( $node->settings->type ) && 'loop' === $node->settings->type ) {
$loops[] = $node;
}
}
// Restore counter after — we set it per-loop below so each loop sees its own paged-N.
$saved_loop_counter = FLBuilderLoop::$loop_counter;
$position = 0;
foreach ( $loops as $node ) {
$css .= self::render_connected_css_for_loop( $node, $position );
$position++;
}
FLBuilderLoop::$loop_counter = $saved_loop_counter;
return $css;
}
/**
* Renders the CSS for a single loop module in the context of
* the WordPress loop so field connections and shortcodes output
* the correct values.
*
* @since 1.5
* @param object $node The loop node
* @return string
*/
static public function render_connected_css_for_loop( $node, $position = 0 ) {
// Match the render-time loop counter so get_paged() picks this loop's paged-N.
FLBuilderLoop::$loop_counter = $position;
$repeater = new FLBuilderModuleDataRepeater( $node->settings );
$children = FLBuilderModel::get_nested_nodes( $node );
$loop_id = $node->node;
$loop_css = '';
$css_map = [];
$index = 1; // Store index to target by :nth-of-type() selector.
if ( ! $repeater->has_items() ) {
return '';
}
while ( $repeater->has_items() ) {
$repeater->setup_item();
foreach ( $children as $child_id => $child ) {
$module = FLBuilderModel::get_module( $child );
if ( ! $module instanceof FLBuilderModule ) {
continue;
}
// Get raw CSS without shortcodes parsed or connections connected.
// We use this to compare to the parsed/connected CSS. If it differs
// then we include it for rendering. If not, we fallback to the CSS
// already rendered in FLBuilder::render_css.
$module_raw_css = FLBuilder::render_module_instance_css( $module );
// Get the CSS with shortcodes parsed or connections connected.
$module->settings = FLBuilderModel::get_node_settings( $child ); // Ensure connections
$module_css = FLBuilder::render_module_instance_css( $module );
$module_css = do_shortcode( $module_css );
// Continue if we don't have unique CSS.
if ( empty( $module_css ) || ( $module_raw_css === $module_css ) ) {
continue;
}
// Remove the builder content class since we will be
// nesting this CSS using the loop class.
$module_css = preg_replace( '/\.fl-builder-content(?:-\d+)?\s*/', '', $module_css );
if ( ! isset( $css_map[ $child_id ] ) ) {
$css_map[ $child_id ] = [];
}
$css_map[ $child_id ][ $index ] = $module_css;
}
$index++; // Increment the index for the next item.
}
$repeater->cleanup();
// Render the CSS in a nested rule for targeting each item.
foreach ( $css_map as $child_id => $child_css_array ) {
foreach ( $child_css_array as $index => $child_css ) {
$loop_class = ".fl-node-$loop_id li.fl-loop-item:nth-of-type($index)";
$loop_css .= "$loop_class { $child_css }";
}
}
return $loop_css;
}
/**
* Is JSON-LD enabled
*
* @since 1.5
*/
public static function json_ld_enabled() {
/**
* Disable all loop module schema markup
* @see fl_post_grid_disable_schema
*/
if ( false !== apply_filters( 'fl_loop_disable_schema', false ) ) {
return false;
} else {
return FLBuilder::is_schema_enabled();
}
}
/**
* Prints JSON-LD for the passed query.
*
* @since 1.5
* @return void
*/
public function print_json_ld( $repeater ) {
$valid_sources = [ 'main_query', 'custom_query', 'acf_repeater' ];
$data_source = isset( $this->settings->data_source ) ? $this->settings->data_source : 'custom_query';
if ( ! $this->json_ld_enabled() || ! in_array( $data_source, $valid_sources ) ) {
return;
}
$post_type = isset( $this->settings->post_type ) ? $this->settings->post_type : 'post';
$collection_type = $this->json_ld_collection_type( $post_type );
$item_type = 'Blog' === $collection_type ? 'BlogPosting' : 'ListItem';
$item_key = 'Blog' === $collection_type ? 'blogPost' : 'itemListElement';
$logo = $this->json_ld_publisher_logo();
$position = 1;
$json_ld = [
'@context' => 'https://schema.org',
'@type' => $collection_type,
'name' => $this->json_ld_page_name(),
'url' => $this->json_ld_page_url(),
$item_key => [],
];
while ( $repeater->has_items() ) {
$repeater->setup_item();
$post_json = [
'@type' => $item_type,
'headline' => esc_html( get_the_title() ),
'url' => esc_url( get_permalink() ),
'datePublished' => esc_html( get_the_date( 'c' ) ),
'dateModified' => esc_html( get_the_modified_date( 'c' ) ),
'description' => esc_html( get_the_excerpt() ),
'mainEntityOfPage' => [
'@type' => 'WebPage',
'@id' => esc_url( get_permalink() ),
],
'author' => [
'@type' => 'Person',
'name' => esc_html( get_the_author() ),
],
'publisher' => [
'@type' => 'Organization',
'name' => esc_html( get_bloginfo( 'name' ) ),
],
'interactionStatistic' => [
'@type' => 'InteractionCounter',
'interactionType' => 'https://schema.org/CommentAction',
'userInteractionCount' => wp_count_comments( get_the_ID() )->approved,
],
];
if ( 'Blog' !== $collection_type ) {
$post_json['position'] = $position;
}
if ( ! empty( $logo ) ) {
$post_json['publisher']['logo'] = [
'@type' => 'ImageObject',
'url' => $logo,
];
}
if ( has_post_thumbnail() ) {
$post_json['image'] = esc_url( get_the_post_thumbnail_url( null, 'full' ) );
}
$json_ld[ $item_key ][] = $post_json;
$position++;
}
$repeater->cleanup();
$encoded = json_encode( $json_ld, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT );
echo '<script type="application/ld+json">' . $encoded . '</script>';
}
/**
* Returns the collection type for JSON-LD.
*
* @since 1.5
* @return string
*/
public function json_ld_collection_type( $post_type = 'post' ) {
$data_source = isset( $this->settings->data_source ) ? $this->settings->data_source : 'custom_query';
if ( is_archive() && 'main_query' === $data_source ) {
return is_post_type_archive( 'post' ) ? 'Blog' : 'ItemList';
}
return FLBuilderUtils::post_type_contains( 'post', $post_type ) ? 'Blog' : 'ItemList';
}
/**
* Returns the page name for JSON-LD
*
* @since 1.5
* @return string
*/
public function json_ld_page_name() {
if ( is_singular() ) {
return get_the_title();
} elseif ( is_category() || is_tag() ) {
return single_term_title( '', false );
} elseif ( is_post_type_archive() ) {
return post_type_archive_title( '', false );
} elseif ( is_author() ) {
return 'Posts by ' . get_the_author();
} elseif ( is_date() ) {
return 'Archives for ' . get_the_date( 'F Y' );
}
return get_bloginfo( 'name' );
}
/**
* Returns the page URL for JSON-LD
*
* @since 1.5
* @return string
*/
public function json_ld_page_url() {
if ( is_singular() ) {
return esc_url( get_permalink() );
} elseif ( is_category() || is_tag() ) {
return esc_url( get_term_link( get_queried_object() ) );
} elseif ( is_post_type_archive() ) {
return esc_url( get_post_type_archive_link( get_query_var( 'post_type' ) ) );
} elseif ( is_author() ) {
return esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) );
} elseif ( is_date() ) {
return esc_url( get_day_link( get_query_var( 'year' ), get_query_var( 'monthnum' ), get_query_var( 'day' ) ) );
}
return esc_url( get_home_url() );
}
/**
* Returns the publisher logo URL for JSON-LD
*
* @since 1.5
* @return string
*/
public function json_ld_publisher_logo() {
$image = '';
if ( class_exists( 'FLTheme' ) && 'image' == FLTheme::get_setting( 'fl-logo-type' ) ) {
$image = FLTheme::get_setting( 'fl-logo-image' );
} elseif ( has_custom_logo() ) {
$custom_logo_id = get_theme_mod( 'custom_logo' );
$logo = wp_get_attachment_image_src( $custom_logo_id, 'full' );
$image = is_array( $logo ) ? $logo[0] : false;
}
return $image;
}
/**
* Render the tag for a non-wrapped module.
*
* @since 1.5
* @return string
*/
public function tag( $tag = 'div' ) {
// Check advanced container setting
if ( '' !== $this->settings->container_element ) {
$tag = $this->settings->container_element;
}
echo $tag;
}
}
FLBuilder::register_module( 'FLLoopModule', array(
'general' => array(
'title' => __( 'General', 'bb-theme-builder' ),
'sections' => array(
'general' => array(
'fields' => array(
'column_sizing' => array(
'label' => __( 'Item Sizing', 'bb-theme-builder' ),
'type' => 'button-group',
'fill_space' => true,
'default' => 'count',
'options' => array(
'count' => __( 'Columns', 'bb-theme-builder' ),
'item_size' => __( 'Item Size', 'bb-theme-builder' ),
),
'toggle' => array(
'count' => array( 'fields' => array( 'column_count' ) ),
'item_size' => array( 'fields' => array( 'min_size', 'max_size' ) ),
),
),
'column_count' => array(
'label' => __( 'Number of Columns', 'bb-theme-builder' ),
'type' => 'unit',
'unit' => '',
'responsive' => array(
'default' => array(
'default' => 3,
'large' => 3,
'medium' => 2,
'responsive' => 1,
),
),
'slider' => array(
'min' => '1',
'max' => '12',
),
'preview' => array(
'type' => 'css',
'auto' => true,
'selector' => '> ul',
'property' => 'grid-template-columns',
'format_value' => 'repeat( %s, minmax( 0, 1fr ))',
'enabled' => array(
'column_sizing' => 'count',
),
),
),
'min_size' => array(
'label' => __( 'Minimum Width', 'bb-theme-builder' ),
'type' => 'unit',
'units' => array( 'px', 'fr' ),
'responsive' => array(
'default' => array(
'default' => '100',
),
'default_unit' => array(
'default' => 'px',
),
),
'slider' => array(
'min' => '100',
'max' => '1000',
),
),
'max_size' => array(
'label' => __( 'Maximum Width', 'bb-theme-builder' ),
'type' => 'unit',
'units' => array( 'px', 'fr' ),
'responsive' => array(
'default' => array(
'default' => '300',
),
'default_unit' => array(
'default' => 'px',
),
),
'slider' => array(
'min' => '100',
'max' => '1000',
),
),
'gap' => array(
'label' => __( 'Gap', 'bb-theme-builder' ),
'type' => 'dimension',
'keys' => array(
'row' => __( 'Row', 'bb-theme-builder' ),
'column' => __( 'Column', 'bb-theme-builder' ),
),
'responsive' => array(
'default' => array(
'default' => '20',
),
'default_unit' => array(
'default' => 'px',
),
),
'units' => array( 'px', 'em', '%', 'vw', 'vh' ),
'slider' => array(
'min' => 0,
'max' => 100,
),
'preview' => array(
'type' => 'css',
'selector' => '> ul',
'property' => 'gap',
'auto' => true,
),
),
),
),
),
),
'content' => array(
'title' => __( 'Content', 'bb-theme-builder' ),
'file' => FL_BUILDER_DIR . 'includes/loop-settings.php',
),
'pagination' => array(
'title' => __( 'Pagination', 'bb-theme-builder' ),
'sections' => array(
'pagination' => array(
'title' => '',
'fields' => array(
'pagination' => array(
'type' => 'select',
'label' => __( 'Pagination', 'bb-theme-builder' ),
'default' => 'numbers',
'options' => array(
'numbers' => __( 'Numbers', 'bb-theme-builder' ),
'scroll' => __( 'Scroll', 'bb-theme-builder' ),
'none' => __( 'None', 'bb-theme-builder' ),
),
'toggle' => array(
'numbers' => array(
'fields' => array( 'pagination_auto_scroll' ),
),
),
),
'pagination_auto_scroll' => array(
'type' => 'select',
'label' => __( 'Auto-scroll on Pagination', 'bb-theme-builder' ),
'default' => '1',
'options' => array(
'1' => __( 'Yes', 'bb-theme-builder' ),
'0' => __( 'No', 'bb-theme-builder' ),
),
),
'posts_per_page' => array(
'type' => 'text',
'label' => __( 'Posts Per Page', 'bb-theme-builder' ),
'default' => '10',
),
'no_results_message' => array(
'type' => 'textarea',
'label' => __( 'No Results Message', 'bb-theme-builder' ),
'default' => __( "Sorry, we couldn't find any posts. Please try a different search.", 'bb-theme-builder' ),
'rows' => 6,
),
'show_search' => array(
'type' => 'select',
'label' => __( 'Show Search', 'bb-theme-builder' ),
'default' => '1',
'options' => array(
'1' => __( 'Show', 'bb-theme-builder' ),
'0' => __( 'Hide', 'bb-theme-builder' ),
),
'help' => __( 'Shows the search form if no items are found.', 'bb-theme-builder' ),
),
),
),
),
),
) );
require_once __DIR__ . '/loop-aliases.php';