diff --git a/includes/class-newspack-listings-api.php b/includes/class-newspack-listings-api.php
index 003e3ee2..f5e6cb28 100644
--- a/includes/class-newspack-listings-api.php
+++ b/includes/class-newspack-listings-api.php
@@ -21,6 +21,12 @@
* Sets up API endpoints and handlers for listings.
*/
final class Newspack_Listings_Api {
+ /**
+ * REST route namespace.
+ *
+ * @var Newspack_Listings_Api
+ */
+ protected static $namespace = 'newspack-listings/v1';
/**
* The single instance of the class.
@@ -56,12 +62,42 @@ public static function register_routes() {
// GET listings posts by ID, query args, or title search term.
register_rest_route(
- 'newspack-listings/v1',
+ self::$namespace,
'listings',
[
[
'methods' => \WP_REST_Server::READABLE,
'callback' => [ __CLASS__, 'get_items' ],
+ 'args' => [
+ 'query' => [
+ 'sanitize_callback' => '\Newspack_Listings\Utils\sanitize_array',
+ ],
+ 'id' => [
+ 'sanitize_callback' => 'absint',
+ ],
+ 'type' => [
+ 'sanitize_callback' => '\Newspack_Listings\Utils\sanitize_array',
+ ],
+ 'attributes' => [
+ 'sanitize_callback' => '\Newspack_Listings\Utils\sanitize_array',
+ ],
+ 'offset' => [
+ 'sanitize_callback' => 'absint',
+ ],
+ 'page' => [
+ 'sanitize_callback' => 'absint',
+ ],
+ 'per_page' => [
+ 'sanitize_callback' => 'absint',
+ ],
+ 'search' => [
+ 'sanitize_callback' => 'sanitize_text_field',
+ ],
+ '_fields' => [
+ 'sanitize_callback' => 'sanitize_text_field',
+ ],
+
+ ],
'permission_callback' => '__return_true',
],
]
@@ -69,7 +105,7 @@ public static function register_routes() {
// GET listings taxonomy terms by name search term.
register_rest_route(
- 'newspack-listings/v1',
+ self::$namespace,
'terms',
[
[
@@ -82,7 +118,7 @@ public static function register_routes() {
// GET listings taxonomy terms by name search term.
register_rest_route(
- 'newspack-listings/v1',
+ self::$namespace,
'children',
[
[
@@ -95,7 +131,7 @@ public static function register_routes() {
// Set listings taxonomy terms.
register_rest_route(
- 'newspack-listings/v1',
+ self::$namespace,
'children',
[
[
@@ -254,6 +290,7 @@ public static function build_listings_query( $query, $args = [] ) {
* @return WP_REST_Response.
*/
public static function get_items( $request ) {
+ $response = [];
$params = $request->get_params();
$fields = explode( ',', $params['_fields'] );
$search = ! empty( $params['search'] ) ? $params['search'] : null;
@@ -297,81 +334,88 @@ public static function get_items( $request ) {
$listings_query = new \WP_Query( $args );
if ( $listings_query->have_posts() ) {
- $response = new \WP_REST_Response(
- array_map(
- function( $post ) use ( $attributes, $fields, $is_amp, $next_page, $query ) {
- $item = [
- 'id' => $post->ID,
- 'title' => $post->post_title,
- ];
-
- // if $fields includes html, get rendered HTML for the post.
- if ( in_array( 'html', $fields ) && ! empty( $attributes ) ) {
- $html = Utils\template_include(
- 'listing',
- [
- 'attributes' => $attributes,
- 'post' => $post,
- ]
- );
-
- // If an AMP page, convert to valid AMP HTML.
- if ( $is_amp ) {
- $html = Utils\generate_amp_partial( $html );
- }
-
- $item['html'] = $html;
+ $listings = array_map(
+ function( $post ) use ( $attributes, $fields, $is_amp, $next_page, $query ) {
+ $item = [
+ 'id' => $post->ID,
+ 'title' => $post->post_title,
+ ];
+
+ // if $fields includes html, get rendered HTML for the post.
+ if ( in_array( 'html', $fields ) && ! empty( $attributes ) ) {
+ $html = Utils\template_include(
+ 'listing',
+ [
+ 'attributes' => $attributes,
+ 'post' => $post,
+ ]
+ );
+
+ // If an AMP page, convert to valid AMP HTML.
+ if ( $is_amp ) {
+ $html = Utils\generate_amp_partial( $html );
}
- // If $fields includes category, get the post categories.
- if ( in_array( 'category', $fields ) ) {
- $item['category'] = get_the_terms( $post->ID, 'category' );
- }
-
- // If $fields includes tags, get the post tags.
- if ( in_array( 'tags', $fields ) ) {
- $item['tags'] = get_the_terms( $post->ID, 'post_tag' );
- }
+ $item['html'] = $html;
+ }
+
+ // If $fields includes category, get the post categories.
+ if ( in_array( 'category', $fields ) ) {
+ $item['category'] = get_the_terms( $post->ID, 'category' );
+ }
+
+ // If $fields includes tags, get the post tags.
+ if ( in_array( 'tags', $fields ) ) {
+ $item['tags'] = get_the_terms( $post->ID, 'post_tag' );
+ }
+
+ // If $fields includes excerpt, get the post excerpt.
+ if ( in_array( 'excerpt', $fields ) ) {
+ $item['excerpt'] = Utils\get_listing_excerpt( $post );
+ }
+
+ // If $fields includes media, get the featured image + caption.
+ if ( in_array( 'media', $fields ) ) {
+ $item['media'] = [
+ 'image' => get_the_post_thumbnail_url( $post->ID, 'medium' ),
+ 'caption' => get_the_post_thumbnail_caption( $post->ID ),
+ ];
+ }
- // If $fields includes author and the post isn't set to hide author, get the post author.
- if ( in_array( 'author', $fields ) && empty( get_post_meta( $post->ID, 'newspack_listings_hide_author', true ) ) ) {
- $item['author'] = get_the_author_meta( 'display_name', $post->post_author );
- }
+ // If $fields includes meta, get all Newspack Listings meta fields.
+ if ( in_array( 'meta', $fields ) || in_array( 'author', $fields ) ) {
+ $item['meta'] = [];
+ $post_meta = Core::get_meta_values( $post->ID, $post->post_type );
- // If $fields includes excerpt, get the post excerpt.
- if ( in_array( 'excerpt', $fields ) ) {
- $item['excerpt'] = Utils\get_listing_excerpt( $post );
+ if ( ! empty( $post_meta ) ) {
+ $item['meta'] = $post_meta;
}
+ }
- // If $fields includes media, get the featured image + caption.
- if ( in_array( 'media', $fields ) ) {
- $item['media'] = [
- 'image' => get_the_post_thumbnail_url( $post->ID, 'medium' ),
- 'caption' => get_the_post_thumbnail_caption( $post->ID ),
- ];
- }
+ // If $fields includes type, get the post type.
+ if ( in_array( 'type', $fields ) ) {
+ $item['type'] = $post->post_type;
+ }
- // If $fields includes meta, get all Newspack Listings meta fields.
- if ( in_array( 'meta', $fields ) ) {
- $post_meta = Core::get_meta_values( $post->ID, $post->post_type );
+ // If $fields includes author and the post isn't set to hide author, get the post author.
+ if ( in_array( 'author', $fields ) && empty( get_post_meta( $post->ID, 'newspack_listings_hide_author', true ) ) ) {
+ $item['author'] = get_the_author_meta( 'display_name', $post->post_author );
+ }
- if ( ! empty( $post_meta ) ) {
- $item['meta'] = $post_meta;
- }
- }
+ $item['test'] = 'Brody';
- // If $fields includes type, get the post type.
- if ( in_array( 'type', $fields ) ) {
- $item['type'] = $post->post_type;
- }
+ // If $fields includes sponsors include sponsors info.
+ if ( in_array( 'sponsors', $fields ) ) {
+ $item['sponsors'] = Utils\get_sponsors( $post->ID, 'native' );
+ }
- return $item;
- },
- $listings_query->posts
- ),
- 200
+ return $item;
+ },
+ $listings_query->posts
);
+ $response = new \WP_REST_Response( $listings );
+
// Provide next URL if there are more pages.
if ( $next_page <= $listings_query->max_num_pages ) {
$next_url = add_query_arg(
@@ -382,18 +426,16 @@ function( $post ) use ( $attributes, $fields, $is_amp, $next_page, $query ) {
'amp' => $is_amp,
'_fields' => 'html',
],
- rest_url( '/newspack-listings/v1/listings' )
+ rest_url( '/' . self::$namespace . '/listings' )
);
}
if ( ! empty( $next_url ) ) {
$response->header( 'next-url', $next_url );
}
-
- return $response;
}
- return new \WP_REST_Response( [] );
+ return rest_ensure_response( $response );
}
/**
diff --git a/includes/class-newspack-listings-core.php b/includes/class-newspack-listings-core.php
index 56314443..19e62329 100644
--- a/includes/class-newspack-listings-core.php
+++ b/includes/class-newspack-listings-core.php
@@ -75,6 +75,7 @@ public function __construct() {
add_filter( 'newspack_listings_hide_author', [ __CLASS__, 'hide_author' ] );
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' ] );
register_activation_hook( NEWSPACK_LISTINGS_FILE, [ __CLASS__, 'activation_hook' ] );
}
@@ -827,6 +828,19 @@ public static function activation_hook() {
flush_rewrite_rules(); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.flush_rewrite_rules_flush_rewrite_rules
}
+ /**
+ * If using the Newspack Sponsors plugin, add support for sponsors to all listings.
+ *
+ * @param array $post_types Array of supported post types.
+ * @return array Filtered array of supported post types.
+ */
+ public static function support_newspack_sponsors( $post_types ) {
+ return array_merge(
+ $post_types,
+ array_values( self::NEWSPACK_LISTINGS_POST_TYPES )
+ );
+ }
+
/**
* Convert legacy custom taxonomies to regular post categories and tags.
* Helpful for sites that have been using v1 of the Listings plugin.
diff --git a/includes/newspack-listings-utils.php b/includes/newspack-listings-utils.php
index 71b9c93f..f3e31097 100644
--- a/includes/newspack-listings-utils.php
+++ b/includes/newspack-listings-utils.php
@@ -346,3 +346,25 @@ function generate_amp_partial( $html ) {
}
return \AMP_DOM_Utils::get_content_from_dom( $dom );
}
+
+/**
+ * Get sponsors for the given listing.
+ *
+ * @param int $post_id ID of the listing.
+ * @param string $scope 'Native' or 'underwritten'.
+ * @param string $type 'Post' or 'archive'.
+ *
+ * @return array|boolean Array of sponsors, or false if none.
+ */
+function get_sponsors( $post_id = null, $scope = null, $type = 'post' ) {
+ // Bail if we don't have the Sponsors plugin.
+ if ( ! function_exists( '\Newspack_Sponsors\get_all_sponsors' ) ) {
+ return false;
+ }
+
+ if ( null === $post_id ) {
+ $post_id = get_the_ID();
+ }
+
+ return \Newspack_Sponsors\get_all_sponsors( $post_id, $scope, $type );
+}
diff --git a/src/assets/shared/listing.scss b/src/assets/shared/listing.scss
index b65f21d3..7b307e42 100644
--- a/src/assets/shared/listing.scss
+++ b/src/assets/shared/listing.scss
@@ -2,6 +2,15 @@
.newspack-listings {
&__listing-post {
+ display: block;
+
+ @media only screen and ( min-width: $tablet_width ) {
+ .media-position-left &,
+ .media-position-right & {
+ display: flex;
+ }
+ }
+
+ .is-link {
padding-left: 0;
padding-right: 0;
@@ -50,18 +59,6 @@
}
}
- &__listing-post,
- &__listing-link {
- display: block;
-
- @media only screen and ( min-width: $tablet_width ) {
- .media-position-left &,
- .media-position-right & {
- display: flex;
- }
- }
- }
-
&__listing-title {
margin-top: 0.5rem;
@@ -125,4 +122,14 @@
&__column-reverse {
flex-direction: row-reverse;
}
+
+ &__sponsors {
+ align-items: center;
+ display: flex;
+
+ .sponsor-logos {
+ border-right: 1px solid var( --newspack-listings--grey-light );
+ margin-right: 0.75rem;
+ }
+ }
}
diff --git a/src/blocks/curated-list/edit.js b/src/blocks/curated-list/edit.js
index 788256b8..f2f069ae 100644
--- a/src/blocks/curated-list/edit.js
+++ b/src/blocks/curated-list/edit.js
@@ -117,7 +117,7 @@ const CuratedListEditorComponent = ( {
const posts = await apiFetch( {
path: addQueryArgs( '/newspack-listings/v1/listings', {
query: { ...query, maxItems: MAX_EDITOR_ITEMS }, // Get up to MAX_EDITOR_ITEMS listings in the editor so we can show all locations.
- _fields: 'id,title,author,category,tags,excerpt,media,meta,type',
+ _fields: 'id,title,author,category,tags,excerpt,media,meta,type,sponsors',
} ),
} );
setAttributes( { listingIds: posts.map( post => post.id ) } );
diff --git a/src/blocks/listing/edit.js b/src/blocks/listing/edit.js
index 49f8bc26..7482f6b2 100644
--- a/src/blocks/listing/edit.js
+++ b/src/blocks/listing/edit.js
@@ -69,7 +69,7 @@ const ListingEditorComponent = ( {
path: addQueryArgs( '/newspack-listings/v1/listings', {
per_page: 100,
id: listingId,
- _fields: 'id,title,author,category,tags,excerpt,media,meta',
+ _fields: 'id,title,author,category,tags,excerpt,media,meta,sponsors',
} ),
} );
diff --git a/src/blocks/listing/listing.js b/src/blocks/listing/listing.js
index 7e66b9f0..f77fab63 100644
--- a/src/blocks/listing/listing.js
+++ b/src/blocks/listing/listing.js
@@ -3,7 +3,7 @@
/**
* WordPress dependencies
*/
-import { __ } from '@wordpress/i18n';
+import { __, _x, sprintf } from '@wordpress/i18n';
import { Notice } from '@wordpress/components';
import { Fragment, RawHTML } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
@@ -11,6 +11,15 @@ import { decodeEntities } from '@wordpress/html-entities';
export const Listing = ( { attributes, error, post } ) => {
// Parent Curated List block attributes.
const { showAuthor, showCategory, showTags, showExcerpt, showImage, showCaption } = attributes;
+ const {
+ author = '',
+ category = [],
+ excerpt = '',
+ media = {},
+ sponsors = false,
+ tags = [],
+ title = '',
+ } = post;
return (
@@ -19,46 +28,83 @@ export const Listing = ( { attributes, error, post } ) => {
{ error }
) }
- { showImage && post && post.media && post.media.image && (
+ { showImage && post && media && media.image && (
) }
- { post && post.title && (
+ { post && (
- { showCategory && post.category.length && ! post.newspack_post_sponsors && (
+ { sponsors && 0 < sponsors.length && (
+
+ { sponsors[ 0 ].sponsor_flag }
+
+ ) }
+ { showCategory && category.length && ! sponsors && (
- { post.category.map( ( category, index ) => (
+ { category.map( ( _category, index ) => (
- { decodeEntities( category.name ) }
- { index + 1 < post.category.length && ', ' }
+ { decodeEntities( _category.name ) }
+ { index + 1 < _category.length && ', ' }
) ) }
) }
-
{ decodeEntities( post.title ) }
- { showAuthor && post.author && (
-
{ __( 'By', 'newpack-listings' ) + ' ' + decodeEntities( post.author ) }
+
{ decodeEntities( title ) }
+ { sponsors && 0 < sponsors.length && (
+
+
+ { sponsors.map( sponsor => {
+ return (
+
+ );
+ } ) }
+
+
+ { sponsors.map( ( sponsor, index ) =>
+ sprintf(
+ '%s%s%s%s',
+ 0 === index ? sponsor.sponsor_byline + ' ' : '',
+ 1 < sponsors.length && index + 1 === sponsors.length
+ ? __( ' and ', 'newspack-listings' )
+ : '',
+ sponsor.sponsor_name,
+ 2 < sponsors.length && index + 1 < sponsors.length
+ ? _x( ', ', 'separator character', 'newspack-listings' )
+ : ''
+ )
+ ) }
+
+
+ ) }
+ { showAuthor && author && ! sponsors && (
+
{ __( 'By', 'newpack-listings' ) + ' ' + decodeEntities( author ) }
) }
- { showExcerpt && post.excerpt &&
{ post.excerpt } }
+ { showExcerpt && excerpt &&
{ excerpt } }
- { showTags && post.tags.length && (
+ { showTags && tags.length && (
{ __( 'Tagged: ', 'newspack-listings' ) }
- { post.tags.map( ( tag, index ) => (
+ { tags.map( ( tag, index ) => (
{ decodeEntities( tag.name ) }
- { index + 1 < post.tags.length && ', ' }
+ { index + 1 < tags.length && ', ' }
) ) }
diff --git a/src/templates/listing.php b/src/templates/listing.php
index d93061d2..5b0e23f3 100644
--- a/src/templates/listing.php
+++ b/src/templates/listing.php
@@ -18,62 +18,139 @@ function( $data ) {
return;
}
+ // Get native sponsors.
+ $sponsors = Utils\get_sponsors( $post->ID, 'native' );
?>
-
-
- ID, 'large' );
- if ( ! empty( $featured_image ) ) :
- ?>
-
+
+
-