diff --git a/includes/class-newspack-listings-core.php b/includes/class-newspack-listings-core.php index 356ba283..eeae71f1 100644 --- a/includes/class-newspack-listings-core.php +++ b/includes/class-newspack-listings-core.php @@ -74,6 +74,8 @@ public function __construct() { add_filter( 'newspack_listings_hide_publish_date', [ __CLASS__, 'hide_publish_date' ] ); add_filter( 'newspack_theme_featured_image_post_types', [ __CLASS__, 'support_featured_image_options' ] ); add_filter( 'newspack_sponsors_post_types', [ __CLASS__, 'support_newspack_sponsors' ] ); + add_filter( 'wpseo_primary_term_taxonomies', [ __CLASS__, 'disable_yoast_primary_categories' ], 10, 2 ); + add_action( 'pre_get_posts', [ __CLASS__, 'enable_listing_category_archives' ], 11 ); register_activation_hook( NEWSPACK_LISTINGS_FILE, [ __CLASS__, 'activation_hook' ] ); } @@ -145,8 +147,9 @@ public static function register_post_types() { $settings = Settings::get_settings(); $prefix = $settings['newspack_listings_permalink_prefix']; $prefix = ! empty( $prefix ) ? $prefix . '/' : ''; + $show_in_archives = ! empty( $settings['newspack_listings_enable_post_type_archives'] ) ? true : false; $default_config = [ - 'has_archive' => false, + 'has_archive' => $show_in_archives, 'public' => true, 'show_in_menu' => 'newspack-listings', 'show_in_rest' => true, @@ -688,7 +691,7 @@ public static function hide_publish_date( $hide_publish_dates = false ) { } /** - * Adds additional utility classes to the body element for single listing pages. + * Adds additional utility classes to the body element for single listing or listing archive pages. * * If using the single-featured or wide templates, apply a body class to listing posts * so that they inherit theme styles for that template. @@ -697,7 +700,24 @@ public static function hide_publish_date( $hide_publish_dates = false ) { * @return array Filtered array of body classes. */ public static function set_template_class( $classes ) { - if ( self::is_listing() ) { + $listing_post_types = array_values( self::NEWSPACK_LISTINGS_POST_TYPES ); + + // If an archive. + if ( is_post_type_archive( $listing_post_types ) || is_category() || is_tag() ) { + $is_all_listings = Utils\all_posts_are_type( $listing_post_types ); + if ( $is_all_listings ) { + $classes[] = 'newspack-listings'; + + // If the "show as grid" option is enabled, let's check if the results are mostly listings. + $show_as_grid = Settings::get_settings( 'newspack_listings_archive_grid' ); + if ( $show_as_grid ) { + $classes[] = 'newspack-listings-grid'; + } + } + } + + // If a singular listing. + if ( is_singular( $listing_post_types ) ) { $classes[] = 'newspack-listings'; $term_classes = Utils\get_term_classes(); $classes = array_merge( $classes, $term_classes ); @@ -734,6 +754,59 @@ public static function support_featured_image_options( $post_types ) { ); } + /** + * Disable the Yoast primary category picker for Listing CPTs. + * + * @param array $taxonomies Array of taxonomies. + * @param string $post_type Post type of the current post. + */ + public static function disable_yoast_primary_categories( $taxonomies, $post_type ) { + $disable_yoast = Settings::get_settings( 'newspack_listings_disable_yoast_primary_categories' ); + + // Disable for all taxonomies on Listing CPTs. + if ( ! is_wp_error( $disable_yoast ) && ! empty( $disable_yoast ) && self::is_listing() ) { + return []; + } + + return $taxonomies; + } + + /** + * Allows listing post types to be displayed in taxonomy term archive pages. + * TODO: Enable re-sorting of query to show featured listings first (requires optimization). + * + * @param WP_Query $query Query. + */ + public static function enable_listing_category_archives( $query ) { + $show_in_archives = Settings::get_settings( 'newspack_listings_enable_term_archives' ); + + // Only if archives are enabled in Settings. + if ( empty( $show_in_archives ) ) { + return; + } + + if ( ! is_admin() && $query->is_main_query() ) { + if ( is_category() || is_tag() ) { + $existing_post_types = $query->get( 'post_type' ); + + // Don't alter the query for templates. + if ( 'wp_template' === $existing_post_types ) { + return; + } + + // If the query has no post type, assume "post" only. + if ( empty( $existing_post_types ) ) { + $existing_post_types = [ 'post' ]; + } + + // Add listings to category/tag archives. + $listing_post_types = array_values( self::NEWSPACK_LISTINGS_POST_TYPES ); + $post_types = array_values( array_merge( $existing_post_types, $listing_post_types ) ); + $query->set( 'post_type', $post_types ); + } + } + } + /** * Flush permalinks on plugin activation, ensuring that post types are registered first. */ diff --git a/includes/class-newspack-listings-settings.php b/includes/class-newspack-listings-settings.php index ddf3d396..2f842fec 100644 --- a/includes/class-newspack-listings-settings.php +++ b/includes/class-newspack-listings-settings.php @@ -27,15 +27,19 @@ public static function init() { */ public static function get_sections() { $sections = [ - 'url' => [ + 'url' => [ 'slug' => 'newspack_listings_url_settings', 'title' => __( 'Permalink Settings', 'newspack-listings' ), ], - 'meta' => [ + 'directory' => [ + 'slug' => 'newspack_listings_directory_settings', + 'title' => __( 'Automated Directory Settings', 'newspack-listings' ), + ], + 'meta' => [ 'slug' => 'newspack_listings_meta_settings', 'title' => __( 'Post Meta Settings', 'newspack-listings' ), ], - 'related' => [ + 'related' => [ 'slug' => 'newspack_listings_related_settings', 'title' => __( 'Related Content Settings', 'newspack-listings' ), ], @@ -101,6 +105,30 @@ public static function get_default_settings() { 'value' => __( 'places', 'newspack-listings' ), 'section' => $sections['url']['slug'], ], + [ + 'description' => __( 'Enables automated archives for each listing type. Archives will use the permalink slugs set above.', 'newspack-listings' ), + 'key' => 'newspack_listings_enable_post_type_archives', + 'label' => __( 'Enable listing type archives', 'newpack-listings' ), + 'type' => 'checkbox', + 'value' => false, + 'section' => $sections['directory']['slug'], + ], + [ + 'description' => __( 'Allows listings to appear in automated category and tag archives.', 'newspack-listings' ), + 'key' => 'newspack_listings_enable_term_archives', + 'label' => __( 'Enable listing category/tag archives', 'newpack-listings' ), + 'type' => 'checkbox', + 'value' => false, + 'section' => $sections['directory']['slug'], + ], + [ + 'description' => __( 'If listing archives are enabled, shows listings-only archives in a grid-like layout.', 'newspack-listings' ), + 'key' => 'newspack_listings_archive_grid', + 'label' => __( 'Show listing archives as grid', 'newpack-listings' ), + 'type' => 'checkbox', + 'value' => false, + 'section' => $sections['directory']['slug'], + ], [ 'description' => __( 'This setting can be overridden per listing.', 'newspack-listings' ), 'key' => 'newspack_listings_hide_author', @@ -117,6 +145,14 @@ public static function get_default_settings() { 'value' => true, 'section' => $sections['meta']['slug'], ], + [ + 'description' => __( 'Disables Yoast primary category functionality for all listings.', 'newspack-listings' ), + 'key' => 'newspack_listings_disable_yoast_primary_categories', + 'label' => __( 'Disable Yoast primary categories', 'newpack-listings' ), + 'type' => 'checkbox', + 'value' => false, + 'section' => $sections['meta']['slug'], + ], [ 'description' => __( 'This setting can be overridden per listing, post, or page.', 'newspack-listings' ), 'key' => 'newspack_listings_hide_parents', @@ -266,7 +302,7 @@ public static function page_init() { ); // Flush permalinks when permalink option is updated. - $is_permalink_option = preg_match( '/newspack_listings_(.*)(_prefix|_slug)/', $setting['key'] ); + $is_permalink_option = preg_match( '/newspack_listings_(.*)(_prefix|_slug|_archives)/', $setting['key'] ); if ( $is_permalink_option ) { add_action( 'update_option_' . $setting['key'], [ __CLASS__, 'flush_permalinks' ], 10, 3 ); } diff --git a/includes/newspack-listings-utils.php b/includes/newspack-listings-utils.php index dc23060e..8b7d573e 100644 --- a/includes/newspack-listings-utils.php +++ b/includes/newspack-listings-utils.php @@ -413,3 +413,29 @@ function( $acc, $tag ) { $tag_classes ); } + +/** + * Check if all posts in the current loop query are the given post type(s). + * + * @param string|array $post_type Post type or array of post types to match against. + * + * @return boolean True if all posts are of the given type(s). + */ +function all_posts_are_type( $post_type = 'post' ) { + global $wp_query; + + if ( ! is_array( $post_type ) ) { + $post_type = [ $post_type ]; + } + + // If all of the items in the first set of results match the given type. + $matches_type = true; + + foreach ( $wp_query->posts as $post ) { + if ( ! in_array( $post->post_type, $post_type ) ) { + $matches_type = false; + } + } + + return $matches_type; +} diff --git a/src/assets/front-end/archives.scss b/src/assets/front-end/archives.scss new file mode 100644 index 00000000..21dc6154 --- /dev/null +++ b/src/assets/front-end/archives.scss @@ -0,0 +1,56 @@ +/* Directory Archives */ +.archive.newspack-listings-grid { + #main { + align-content: flex-start; + display: flex; + flex-wrap: wrap; + + @media ( min-width: 600px ) { + margin-left: -1rem; + margin-right: -1rem; + } + @media ( min-width: 782px ) { + width: calc( 65% + 40px ); + } + } + + .navigation.pagination { + width: 100%; + } + + .site-main > article { + display: block; + margin: 0 0 3rem; + position: relative; + width: 100%; + + .listing-label { + position: absolute; + top: -0.5rem; + } + + .entry-title { + font-size: 0.75rem; + text-transform: uppercase; + } + + @media ( min-width: 600px ) { + border: 1rem solid transparent; + flex: 1 0 50%; + max-width: 50%; + } + @media ( min-width: 1200px ) { + flex: 1 0 33%; + max-width: 33%; + } + } + + .has-post-thumbnail .post-thumbnail { + margin-bottom: 0.5rem; + max-width: 100%; + + img { + object-position: 0 0; + } + } +} diff --git a/src/assets/front-end/view.scss b/src/assets/front-end/view.scss index 95401f73..d42a79f3 100644 --- a/src/assets/front-end/view.scss +++ b/src/assets/front-end/view.scss @@ -1,3 +1,4 @@ +@import './archives'; @import './curated-list'; @import './event'; @import './listing';