Post type => label. */ public function eligible_post_types(): array { return Eligibility::post_types(); } /** * Fetches the posts for a feed. * * All selected post types are queried together, so the newest-first order and * the item limit apply to the combined results. Taxonomy filters combine with * AND between taxonomies and OR between the terms of one taxonomy. A post type * that does not use a filtered taxonomy cannot match and is left out of the query. * * @param Feed_Config $config Feed configuration. * @return \WP_Post[]|\WP_Error */ public function fetch( Feed_Config $config ) { foreach ( $config->post_types as $post_type ) { if ( ! Eligibility::is_post_type_eligible( $post_type ) ) { return new \WP_Error( 'feedweaver_post_type', __( 'A selected content type is not publicly available.', 'feedweaver' ) ); } } $types = $config->post_types; $tax_query = array( 'relation' => 'AND' ); foreach ( $config->tax_filters as $taxonomy => $term_ids ) { if ( ! Eligibility::is_taxonomy_eligible( $taxonomy ) ) { return new \WP_Error( 'feedweaver_taxonomy', __( 'A selected taxonomy filter is not available.', 'feedweaver' ) ); } $types = array_values( array_filter( $types, static function ( $type ) use ( $taxonomy ) { return is_object_in_taxonomy( $type, $taxonomy ); } ) ); $tax_query[] = array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => array_map( 'intval', $term_ids ), 'operator' => 'IN', 'include_children' => is_taxonomy_hierarchical( $taxonomy ), ); } if ( ! $types ) { return array(); } $args = array( 'post_type' => $types, 'post_status' => 'publish', 'has_password' => false, 'posts_per_page' => max( 1, min( Feed_Config::MAX_ITEMS, $config->limit ) ), // Newest first; the ID makes the order deterministic when dates are equal. 'orderby' => array( 'date' => 'DESC', 'ID' => 'DESC', ), 'no_found_rows' => true, 'ignore_sticky_posts' => true, ); if ( count( $tax_query ) > 1 ) { $args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- bounded, indexed query. } $query = new \WP_Query( $args ); // Prime caches in bulk so large feeds do not run a query per post. Term caches are // primed by WP_Query itself (update_post_term_cache defaults to true). update_post_thumbnail_cache( $query ); cache_users( array_unique( wp_list_pluck( $query->posts, 'post_author' ) ) ); $posts = array(); foreach ( $query->posts as $post ) { if ( $this->is_eligible( $post ) ) { $posts[] = $post; } } return $posts; } /** * Defence in depth: never trust the query alone. * * @param \WP_Post $post Post. * @return bool */ public function is_eligible( \WP_Post $post ): bool { return 'publish' === $post->post_status && '' === $post->post_password && is_post_publicly_viewable( $post ); } }