Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 190
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Newspack_Blocks_API
0.00% covered (danger)
0.00%
0 / 189
0.00% covered (danger)
0.00%
0 / 10
1056
0.00% covered (danger)
0.00%
0 / 1
 newspack_blocks_get_image_src
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
6
 newspack_blocks_get_primary_category
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
42
 newspack_blocks_get_cat_tag_classes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 newspack_blocks_sponsor_info
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
20
 newspack_blocks_has_custom_excerpt
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 register_video_playlist_endpoint
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 video_playlist_endpoint
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 posts_endpoint
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
110
 specific_posts_endpoint
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
20
 add_post_title_wildcard_search
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Register Newspack Blocks rest fields
4 *
5 * @package Newspack_Blocks
6 */
7
8/**
9 * `Newspack_Blocks_API` is a wrapper for `register_rest_fields()`
10 */
11class Newspack_Blocks_API {
12    /**
13     * Get thumbnail featured image source for the rest field.
14     *
15     * @param array $object_info The object info.
16     * @return array | bool Featured image if available, false if not.
17     */
18    public static function newspack_blocks_get_image_src( $object_info ) {
19        $featured_image_set = [];
20
21        if ( 0 === $object_info['featured_media'] ) {
22            return false;
23        }
24
25        // Large image.
26        $feat_img_array_large        = wp_get_attachment_image_src(
27            $object_info['featured_media'],
28            'large',
29            false
30        );
31        $featured_image_set['large'] = $feat_img_array_large[0] ?? null;
32
33        // Landscape image.
34        $landscape_size = Newspack_Blocks::image_size_for_orientation( 'landscape' );
35
36        $feat_img_array_landscape        = wp_get_attachment_image_src(
37            $object_info['featured_media'],
38            $landscape_size,
39            false
40        );
41        $featured_image_set['landscape'] = $feat_img_array_landscape[0] ?? null;
42
43        // Portrait image.
44        $portrait_size = Newspack_Blocks::image_size_for_orientation( 'portrait' );
45
46        $feat_img_array_portrait        = wp_get_attachment_image_src(
47            $object_info['featured_media'],
48            $portrait_size,
49            false
50        );
51        $featured_image_set['portrait'] = $feat_img_array_portrait[0] ?? null;
52
53        // Square image.
54        $square_size = Newspack_Blocks::image_size_for_orientation( 'square' );
55
56        $feat_img_array_square        = wp_get_attachment_image_src(
57            $object_info['featured_media'],
58            $square_size,
59            false
60        );
61        $featured_image_set['square'] = $feat_img_array_square[0] ?? null;
62
63        // Uncropped image.
64        $uncropped_size = 'newspack-article-block-uncropped';
65
66        $feat_img_array_uncropped        = wp_get_attachment_image_src(
67            $object_info['featured_media'],
68            $uncropped_size,
69            false
70        );
71        $featured_image_set['uncropped'] = $feat_img_array_uncropped[0] ?? null;
72
73        return $featured_image_set;
74    }
75
76    /**
77     * Get primary category for the rest field.
78     *
79     * @param array $object_info The object info.
80     * @return string Category name.
81     */
82    public static function newspack_blocks_get_primary_category( $object_info ) {
83        $category = false;
84
85        // Use Yoast primary category if set.
86        if ( class_exists( 'WPSEO_Primary_Term' ) ) {
87            $primary_term = new WPSEO_Primary_Term( 'category', $object_info['id'] );
88            $category_id  = $primary_term->get_primary_term();
89            if ( $category_id ) {
90                $category = get_term( $category_id );
91            }
92        }
93
94        if ( ! $category ) {
95            $categories_list = get_the_category( $object_info['id'] );
96            if ( ! empty( $categories_list ) ) {
97                $category = $categories_list[0];
98            }
99        }
100
101        if ( ! $category ) {
102            return '';
103        }
104
105        $linked_category = '<a href="#">' . $category->name . '</a>';
106
107        return apply_filters( 'newspack_blocks_categories', $linked_category );
108    }
109
110    /**
111     * Get a list of category, tag classes for the rest field.
112     *
113     * @param array $object_info The object info.
114     * @return string classes from assigned categories and tags.
115     */
116    public static function newspack_blocks_get_cat_tag_classes( $object_info ) {
117        return Newspack_Blocks::get_term_classes( $object_info['id'] );
118    }
119
120    /**
121     * Get all sponsor information for the rest field.
122     *
123     * @param array $object_info The object info.
124     * @return array sponsor information.
125     */
126    public static function newspack_blocks_sponsor_info( $object_info ) {
127        $sponsors = Newspack_Blocks::get_all_sponsors(
128            $object_info['id'],
129            'native',
130            'post',
131            array(
132                'maxwidth'  => 80,
133                'maxheight' => 40,
134            )
135        );
136        if ( ! empty( $sponsors ) ) {
137            $sponsor_info = [];
138            foreach ( $sponsors as $sponsor ) {
139                $sponsor_info_item = [
140                    'flag'          => $sponsor['sponsor_flag'],
141                    'sponsor_name'  => $sponsor['sponsor_name'],
142                    'sponsor_url'   => $sponsor['sponsor_url'],
143                    'byline_prefix' => $sponsor['sponsor_byline'],
144                    'id'            => $sponsor['sponsor_id'],
145                    'scope'         => $sponsor['sponsor_scope'],
146                ];
147                if ( ! empty( $sponsor['sponsor_logo'] ) ) {
148                    $sponsor_info_item['src']        = $sponsor['sponsor_logo']['src'];
149                    $sponsor_info_item['img_width']  = $sponsor['sponsor_logo']['img_width'];
150                    $sponsor_info_item['img_height'] = $sponsor['sponsor_logo']['img_height'];
151                }
152                $sponsor_info[] = $sponsor_info_item;
153            }
154            return $sponsor_info;
155        }
156
157        return false;
158    }
159
160    /**
161     * Pass whether there is a custom excerpt to the editor.
162     *
163     * @param array $object_info The object info.
164     * @return boolean custom excerpt status.
165     */
166    public static function newspack_blocks_has_custom_excerpt( $object_info ) {
167        $post_has_custom_excerpt = has_excerpt( $object_info['id'] );
168        return $post_has_custom_excerpt;
169    }
170
171    /**
172     * Register the video-playlist endpoint.
173     */
174    public static function register_video_playlist_endpoint() {
175        register_rest_route(
176            'newspack-blocks/v1',
177            '/video-playlist',
178            [
179                'methods'             => 'GET',
180                'callback'            => [ 'Newspack_Blocks_API', 'video_playlist_endpoint' ],
181                'permission_callback' => function() {
182                    return current_user_can( 'edit_posts' );
183                },
184            ]
185        );
186    }
187
188    /**
189     * Process requests to the video-playlist endpoint.
190     *
191     * @param WP_REST_Request $request Request object.
192     * @return WP_REST_Response.
193     */
194    public static function video_playlist_endpoint( $request ) {
195        $args = $request->get_params();
196        return new \WP_REST_Response( newspack_blocks_get_video_playlist( $args ), 200 );
197    }
198
199    /**
200     * Posts endpoint
201     *
202     * @param WP_REST_Request $request Request object.
203     * @return WP_REST_Response.
204     */
205    public static function posts_endpoint( $request ) {
206        $attributes = $request->get_params();
207        $args       = Newspack_Blocks::build_articles_query( $attributes, apply_filters( 'newspack_blocks_block_name', 'newspack-blocks/homepage-articles' ) );
208
209        if ( $attributes['exclude'] && count( $attributes['exclude'] ) ) {
210            $args['post__not_in'] = $attributes['exclude']; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in
211        }
212
213        if ( $attributes['include'] && count( $attributes['include'] ) ) {
214            $args['post__in'] = $attributes['include'];
215            $args['orderby']  = 'post__in';
216            $args['order']    = 'ASC';
217        }
218
219        if ( isset( $attributes['showExcerpt'], $attributes['excerptLength'] ) ) {
220            $block_attributes = [
221                'showExcerpt'   => $attributes['showExcerpt'],
222                'excerptLength' => $attributes['excerptLength'],
223            ];
224            Newspack_Blocks::filter_excerpt( $block_attributes );
225        }
226
227        $query = new WP_Query( $args );
228        $posts = [];
229
230        foreach ( $query->posts as $post ) {
231            $GLOBALS['post'] = $post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
232            setup_postdata( $post );
233
234            // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
235            $excerpt = apply_filters( 'get_the_excerpt', $post->post_excerpt, $post );
236            $excerpt = apply_filters( 'the_excerpt', $excerpt );
237            $content = apply_filters( 'the_content', $post->post_content );
238            // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
239
240            $meta = new WP_REST_Post_Meta_Fields( 'post' );
241            $data = [
242                'author'              => (int) $post->post_author,
243                'content'             => [
244                    'rendered' => post_password_required( $post ) ? '' : $content,
245                ],
246                'date'                => Newspack_Blocks::get_displayed_post_date( $post ),
247                'date_formatted'      => Newspack_Blocks::get_formatted_displayed_post_date( $post ),
248                'article_meta_footer' => Newspack_Blocks::get_article_meta_footer( $post ),
249                'excerpt'             => [
250                    'rendered' => post_password_required( $post ) ? '' : $excerpt,
251                ],
252                'full_content'        => get_the_content( $post->ID ),
253                'featured_media'      => (int) get_post_thumbnail_id( $post->ID ),
254                'id'                  => $post->ID,
255                'meta'                => $meta->get_value( $post->ID, $request ),
256                'title'               => [
257                    'rendered' => get_the_title( $post->ID ),
258                ],
259            ];
260
261            $sponsors = Newspack_Blocks::get_all_sponsors( $post->ID );
262            $author_info = Newspack_Blocks::prepare_authors();
263            $add_ons  = [
264                'newspack_article_classes'          => Newspack_Blocks::get_term_classes( $data['id'] ),
265                'newspack_category_info'            => self::newspack_blocks_get_primary_category( $data ),
266                'newspack_featured_image_caption'   => Newspack_Blocks::get_image_caption( $data['featured_media'], $attributes['showCaption'], $attributes['showCredit'] ),
267                'newspack_featured_image_src'       => self::newspack_blocks_get_image_src( $data ),
268                'newspack_has_custom_excerpt'       => self::newspack_blocks_has_custom_excerpt( $data ),
269                'newspack_post_sponsors'            => self::newspack_blocks_sponsor_info( $data ),
270                'newspack_sponsors_show_author'     => Newspack_Blocks::newspack_display_sponsors_and_authors( $sponsors ),
271                'newspack_sponsors_show_categories' => Newspack_Blocks::newspack_display_sponsors_and_categories( $sponsors ),
272                'newspack_post_avatars'             => \newspack_blocks_format_avatars( $author_info ),
273                'newspack_post_byline'              => \newspack_blocks_format_byline( $author_info ),
274                'post_status'                       => $post->post_status,
275                'post_type'                         => $post->post_type,
276                'post_link'                         => Newspack_Blocks::get_post_link( $post->ID ),
277            ];
278
279            // Support Newspack Listings hide author/publish date options.
280            if ( class_exists( 'Newspack_Listings\Core' ) ) {
281                $add_ons['newspack_listings_hide_author']       = apply_filters( 'newspack_listings_hide_author', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
282                $add_ons['newspack_listings_hide_publish_date'] = apply_filters( 'newspack_listings_hide_publish_date', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
283            }
284
285            $posts[] = array_merge( $data, $add_ons );
286        }
287
288        Newspack_Blocks::remove_excerpt_filter();
289
290        return new \WP_REST_Response( $posts );
291    }
292
293    /**
294     * Lookup individual posts by title only.
295     *
296     * @param WP_REST_Request $request Request object.
297     * @return WP_REST_Response.
298     */
299    public static function specific_posts_endpoint( $request ) {
300        $params = $request->get_params();
301        if ( empty( $params['search'] ) ) {
302            return new \WP_REST_Response( [] );
303        }
304        add_filter( 'posts_where', [ 'Newspack_Blocks_API', 'add_post_title_wildcard_search' ], 10, 2 );
305
306        $args = [
307            'post_status'           => 'publish',
308            'title_wildcard_search' => esc_sql( $params['search'] ),
309            'posts_per_page'        => $params['postsToShow'],
310        ];
311
312        if ( $params['postType'] && count( $params['postType'] ) ) {
313            $args['post_type'] = $params['postType'];
314        } else {
315            $args['post_type'] = 'post';
316        }
317
318        $query = new WP_Query( $args );
319        remove_filter( 'posts_where', [ 'Newspack_Blocks_API', 'add_post_title_wildcard_search' ], 10, 2 );
320        return new \WP_REST_Response(
321            array_map(
322                function( $post ) {
323                    return [
324                        'id'    => $post->ID,
325                        'title' => $post->post_title,
326                    ];
327                },
328                $query->posts
329            ),
330            200
331        );
332    }
333
334    /**
335     * Add title wildcard search to post lookup query.
336     *
337     * @param String   $where Where clause.
338     * @param WP_Query $query The query.
339     */
340    public static function add_post_title_wildcard_search( $where, $query ) {
341        $search = ! empty( $query->query['title_wildcard_search'] ) ? $query->query['title_wildcard_search'] : null;
342        $where .= ' AND post_title LIKE "%' . $search . '%" ';
343        return $where;
344    }
345}
346
347add_action( 'rest_api_init', array( 'Newspack_Blocks_API', 'register_video_playlist_endpoint' ) );