<?php
/**
 * Genesis Framework.
 *
 * WARNING: This file is part of the core Genesis Framework. DO NOT edit this file under any circumstances.
 * Please do all modifications in the form of a child theme.
 *
 * @package Genesis\Loops
 * @author  StudioPress
 * @license GPL-2.0-or-later
 * @link    https://my.studiopress.com/themes/genesis/
 */

add_action( 'genesis_loop', 'genesis_do_loop' );
/**
 * Attach a loop to the `genesis_loop` output hook so we can get some front-end output.
 *
 * @since 1.1.0
 */
function genesis_do_loop() {

	if ( is_singular( 'page' ) && genesis_get_custom_field( 'query_args' ) ) {

		$paged = get_query_var( 'paged' ) ?: 1;

		/*
		 * Convert custom field string to args array.
		 */
		$query_args = wp_parse_args(
			genesis_get_custom_field( 'query_args' ),
			[
				'paged' => $paged,
			]
		);

		genesis_custom_loop( $query_args );
	} else {
		genesis_standard_loop();
	}

}

/**
 * Standard loop, meant to be executed without modification in most circumstances where content needs to be displayed.
 *
 * It outputs basic wrapping HTML, but uses hooks to do most of its content output like title, content, post information
 * and comments.
 *
 * The action hooks called are:
 *
 *  - `genesis_before_entry`
 *  - `genesis_entry_header`
 *  - `genesis_before_entry_content`
 *  - `genesis_entry_content`
 *  - `genesis_after_entry_content`
 *  - `genesis_entry_footer`
 *  - `genesis_after_endwhile`
 *  - `genesis_loop_else` (only if no posts were found)
 *
 * @since 1.1.0
 *
 * @return void Return early after legacy loop if not supporting HTML5.
 */
function genesis_standard_loop() {

	if ( have_posts() ) {

		/**
		 * Fires inside the standard loop, before the while() block.
		 *
		 * @since 2.1.0
		 */
		do_action( 'genesis_before_while' );

		while ( have_posts() ) {

			the_post();

			/**
			 * Fires inside the standard loop, before the entry opening markup.
			 *
			 * @since 2.0.0
			 */
			do_action( 'genesis_before_entry' );

			genesis_markup(
				[
					'open'    => '<article %s>',
					'context' => 'entry',
				]
			);

			/**
			 * Fires inside the standard loop, to display the entry header.
			 *
			 * @since 2.0.0
			 */
			do_action( 'genesis_entry_header' );

			/**
			 * Fires inside the standard loop, after the entry header action hook, before the entry content.
			 * opening markup.
			 *
			 * @since 2.0.0
			 */
			do_action( 'genesis_before_entry_content' );

			genesis_markup(
				[
					'open'    => '<div %s>',
					'context' => 'entry-content',
				]
			);
			/**
			 * Fires inside the standard loop, inside the entry content markup.
			 *
			 * @since 2.0.0
			 */
			do_action( 'genesis_entry_content' );
			genesis_markup(
				[
					'close'   => '</div>',
					'context' => 'entry-content',
				]
			);

			/**
			 * Fires inside the standard loop, before the entry footer action hook, after the entry content.
			 * opening markup.
			 *
			 * @since 2.0.0
			 */
			do_action( 'genesis_after_entry_content' );

			/**
			 * Fires inside the standard loop, to display the entry footer.
			 *
			 * @since 2.0.0
			 */
			do_action( 'genesis_entry_footer' );

			genesis_markup(
				[
					'close'   => '</article>',
					'context' => 'entry',
				]
			);

			/**
			 * Fires inside the standard loop, after the entry closing markup.
			 *
			 * @since 2.0.0
			 */
			do_action( 'genesis_after_entry' );

		} // End of one post.

		/**
		 * Fires inside the standard loop, after the while() block.
		 *
		 * @since 1.0.0
		 */
		do_action( 'genesis_after_endwhile' );

	} else { // If no posts exist.

		/**
		 * Fires inside the standard loop when they are no posts to show.
		 *
		 * @since 1.0.0
		 */
		do_action( 'genesis_loop_else' );

	} // End loop.

}

/**
 * Custom loop, meant to be executed when a custom query is needed.
 *
 * It accepts arguments in query_posts style format to modify the custom `WP_Query` object.
 *
 * It outputs basic wrapping HTML, but uses hooks to do most of its content output like title, content, post information,
 * and comments.
 *
 * The arguments can be passed in via the `genesis_custom_loop_args` filter.
 *
 * The action hooks called are the same as {@link genesis_standard_loop()}.
 *
 * @since 1.1.0
 *
 * @global WP_Query $wp_query Query object.
 * @global int      $more
 *
 * @param array $args Loop configuration.
 */
function genesis_custom_loop( $args = [] ) {

	global $wp_query, $more;

	$defaults = []; // For forward compatibility.
	$args     = apply_filters( 'genesis_custom_loop_args', wp_parse_args( $args, $defaults ), $args, $defaults );

	$wp_query = new WP_Query( $args ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Reset later.

	// Only set $more to 0 if we're on an archive.
	$more = is_singular() ? $more : 0; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Handle archives.

	genesis_standard_loop();

	// Restore original query.
	wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query -- Making sure the query is really reset.

}

/**
 * The grid loop - a specific implementation of a custom loop.
 *
 * Outputs markup compatible with a Feature + Grid style layout.
 *
 * The arguments can be filtered by the `genesis_grid_loop_args` filter.
 *
 * @since 1.5.0
 *
 * @global array $_genesis_loop_args Associative array for grid loop configuration.
 *
 * @param array $args Associative array for grid loop configuration.
 */
function genesis_grid_loop( $args = [] ) {

	// Global vars.
	global $_genesis_loop_args;

	// Parse args.
	$args = apply_filters(
		'genesis_grid_loop_args',
		wp_parse_args(
			$args,
			[
				'features'              => 2,
				'features_on_all'       => false,
				'feature_image_size'    => 0,
				'feature_image_class'   => 'alignleft',
				'feature_content_limit' => 0,
				'grid_image_size'       => 'thumbnail',
				'grid_image_class'      => 'alignleft',
				'grid_content_limit'    => 0,
				'more'                  => __( 'Read more', 'genesis' ) . '&#x02026;',
			]
		)
	);

	// If user chose more features than posts per page, adjust features.
	if ( get_option( 'posts_per_page' ) < $args['features'] ) {
		$args['features'] = get_option( 'posts_per_page' );
	}

	// What page are we on?
	$paged = get_query_var( 'paged' ) ?: 1;

	// Potentially remove features on page 2+.
	if ( $paged > 1 && ! $args['features_on_all'] ) {
		$args['features'] = 0;
	}

	// Set global loop args.
	$_genesis_loop_args = $args;

	// Remove some unnecessary stuff from the grid loop.
	remove_action( 'genesis_entry_header', 'genesis_do_post_format_image', 4 );
	remove_action( 'genesis_entry_content', 'genesis_do_post_image', 8 );
	remove_action( 'genesis_entry_content', 'genesis_do_post_content' );
	remove_action( 'genesis_entry_content', 'genesis_do_post_content_nav', 12 );
	remove_action( 'genesis_entry_content', 'genesis_do_post_permalink', 14 );

	// Custom loop output.
	add_filter( 'post_class', 'genesis_grid_loop_post_class' );
	add_action( 'genesis_entry_content', 'genesis_grid_loop_content' );

	// The loop.
	genesis_standard_loop();

	// Reset loops.
	genesis_reset_loops();
	remove_filter( 'post_class', 'genesis_grid_loop_post_class' );
	remove_action( 'genesis_entry_content', 'genesis_grid_loop_content' );

}

/**
 * Filter the post classes to output custom classes for the feature and grid layout.
 *
 * Based on the grid loop args and the loop counter.
 *
 * Applies the `genesis_grid_loop_post_class` filter.
 *
 * The `&1` is a test to see if it is odd. `2&1 = 0` (even), `3&1 = 1` (odd).
 *
 * @since 1.5.0
 *
 * @global array    $_genesis_loop_args Associative array for grid loop config.
 * @global WP_Query $wp_query           Query object.
 *
 * @param array $classes Existing post classes.
 * @return array Amended post classes.
 */
function genesis_grid_loop_post_class( array $classes ) {

	global $_genesis_loop_args, $wp_query;

	$grid_classes = [];

	if ( $_genesis_loop_args['features'] && $wp_query->current_post < $_genesis_loop_args['features'] ) {
		$grid_classes[] = 'genesis-feature';
		$grid_classes[] = sprintf( 'genesis-feature-%s', $wp_query->current_post + 1 );
		$grid_classes[] = $wp_query->current_post & 1 ? 'genesis-feature-even' : 'genesis-feature-odd';
	} elseif ( $_genesis_loop_args['features'] & 1 ) {
		$grid_classes[] = 'genesis-grid';
		$grid_classes[] = sprintf( 'genesis-grid-%s', $wp_query->current_post - $_genesis_loop_args['features'] + 1 );
		$grid_classes[] = $wp_query->current_post & 1 ? 'genesis-grid-odd' : 'genesis-grid-even';
	} else {
		$grid_classes[] = 'genesis-grid';
		$grid_classes[] = sprintf( 'genesis-grid-%s', $wp_query->current_post - $_genesis_loop_args['features'] + 1 );
		$grid_classes[] = $wp_query->current_post & 1 ? 'genesis-grid-even' : 'genesis-grid-odd';
	}

	return array_merge( $classes, apply_filters( 'genesis_grid_loop_post_class', $grid_classes ) );

}

/**
 * Output specially formatted content, based on the grid loop args.
 *
 * @since 1.5.0
 *
 * @global array $_genesis_loop_args Associative array for grid loop configuration.
 */
function genesis_grid_loop_content() {

	global $_genesis_loop_args;

	if ( in_array( 'genesis-feature', get_post_class(), true ) ) {
		if ( $_genesis_loop_args['feature_image_size'] ) {

			$image = genesis_get_image(
				[
					'size'    => $_genesis_loop_args['feature_image_size'],
					'context' => 'grid-loop-featured',
					'attr'    => genesis_parse_attr(
						'entry-image-grid-loop',
						[
							'class' => $_genesis_loop_args['feature_image_class'],
						]
					),
				]
			);

			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $image is html markup.
			printf( '<a href="%s">%s</a>', esc_url( get_permalink() ), $image );

		}

		if ( $_genesis_loop_args['feature_content_limit'] ) {
			the_content_limit( (int) $_genesis_loop_args['feature_content_limit'], genesis_a11y_more_link( esc_html( $_genesis_loop_args['more'] ) ) );
		} else {
			the_content( genesis_a11y_more_link( esc_html( $_genesis_loop_args['more'] ) ) );
		}
	} else {
		if ( $_genesis_loop_args['grid_image_size'] ) {

			$image = genesis_get_image(
				[
					'size'    => $_genesis_loop_args['grid_image_size'],
					'context' => 'grid-loop',
					'attr'    => genesis_parse_attr(
						'entry-image-grid-loop',
						[
							'class' => $_genesis_loop_args['grid_image_class'],
						]
					),
				]
			);

			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $image is html markup.
			printf( '<a href="%s">%s</a>', esc_url( get_permalink() ), $image );

		}

		if ( $_genesis_loop_args['grid_content_limit'] ) {
			the_content_limit( (int) $_genesis_loop_args['grid_content_limit'], genesis_a11y_more_link( esc_html( $_genesis_loop_args['more'] ) ) );
		} else {
			the_excerpt();
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- genesis_a11y_more_link returns html markup.
			printf( '<a href="%s" class="more-link">%s</a>', esc_url( get_permalink() ), genesis_a11y_more_link( esc_html( $_genesis_loop_args['more'] ) ) );
		}
	}

}

add_action( 'genesis_after_entry', 'genesis_add_id_to_global_exclude', 9 );
/**
 * Modify the global $_genesis_displayed_ids each time a loop iterates.
 *
 * Keep track of what posts have been shown on any given page by adding each ID to a global array, which can be used any
 * time by other loops to prevent posts from being displayed twice on a page.
 *
 * @since 2.0.0
 *
 * @global array $_genesis_displayed_ids Array of displayed post IDs.
 */
function genesis_add_id_to_global_exclude() {

	global $_genesis_displayed_ids;

	$_genesis_displayed_ids[] = get_the_ID();

}
