Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 312
0.00% covered (danger)
0.00%
0 / 3
CRAP
n/a
0 / 0
newspack_blocks_render_block_carousel
0.00% covered (danger)
0.00%
0 / 195
0.00% covered (danger)
0.00%
0 / 1
3080
newspack_blocks_carousel_block_autoplay_ui
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
newspack_blocks_register_carousel
0.00% covered (danger)
0.00%
0 / 111
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Server-side rendering of the `newspack-blocks/carousel` block.
4 *
5 * @package WordPress
6 */
7
8/**
9 * Renders the `newspack-blocks/carousel` block on server.
10 *
11 * @param array $attributes The block attributes.
12 *
13 * @return string Returns the post content with latest posts added.
14 */
15function newspack_blocks_render_block_carousel( $attributes ) {
16    static $newspack_blocks_carousel_id = 0;
17    global $newspack_blocks_post_id;
18
19    // This will let the FSE plugin know we need CSS/JS now.
20    do_action( 'newspack_blocks_render_post_carousel' );
21
22    $newspack_blocks_carousel_id++;
23    $autoplay = isset( $attributes['autoplay'] ) ? $attributes['autoplay'] : false;
24    $delay    = isset( $attributes['delay'] ) ? absint( $attributes['delay'] ) : 3;
25    $authors  = isset( $attributes['authors'] ) ? $attributes['authors'] : array();
26
27    $other = array();
28    if ( $autoplay ) {
29        $other[] = 'wp-block-newspack-blocks-carousel__autoplay-playing';
30    }
31    $other[] = 'slides-per-view-' . $attributes['slidesPerView'];
32    $other[] = 'wpnbpc';
33    $classes = Newspack_Blocks::block_classes( 'carousel', $attributes, $other );
34
35    $article_query = new WP_Query( Newspack_Blocks::build_articles_query( $attributes, apply_filters( 'newspack_blocks_block_name', 'newspack-blocks/carousel' ) ) );
36    if ( false === $article_query->have_posts() ) {
37        return '';
38    }
39
40    $counter = 0;
41
42    ob_start();
43    if ( $article_query->have_posts() ) :
44        while ( $article_query->have_posts() ) :
45            $article_query->the_post();
46            $post_id                             = get_the_ID();
47            $authors                             = Newspack_Blocks::prepare_authors();
48            $newspack_blocks_post_id[ $post_id ] = true;
49
50            $article_classes = [
51                'post-has-image',
52                'swiper-slide',
53            ];
54
55            // Add classes based on the post's assigned categories and tags.
56            $article_classes[] = Newspack_Blocks::get_term_classes( $post_id );
57
58            // Get sponsors for this post.
59            $sponsors = Newspack_Blocks::get_all_sponsors( $post_id );
60
61            $counter++;
62            $has_featured_image = has_post_thumbnail();
63            $post_type          = get_post_type();
64            $post_link          = Newspack_Blocks::get_post_link( $post_id );
65
66            // Support Newspack Listings hide author/publish date options.
67            $hide_author       = apply_filters( 'newspack_listings_hide_author', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
68            $hide_publish_date = apply_filters( 'newspack_listings_hide_publish_date', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
69            $show_author       = $attributes['showAuthor'] && ! $hide_author;
70            $show_date         = $attributes['showDate'] && ! $hide_publish_date;
71            $show_caption      = $attributes['showCaption'];
72            $show_credit       = $attributes['showCredit'];
73
74            // Validate the value of the "image fit" attribute.
75            $image_fits = [ 'cover', 'contain' ];
76            $image_fit  = in_array( $attributes['imageFit'], $image_fits, true ) ? $attributes['imageFit'] : $image_fits[0];
77            ?>
78
79            <article data-post-id="<?php echo esc_attr( $post_id ); ?>" class="<?php echo esc_attr( implode( ' ', $article_classes ) . ' ' . $post_type ); ?>">
80                <?php echo Newspack_Blocks::get_post_status_label(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
81                <figure class="post-thumbnail">
82                    <?php if ( $post_link ) : ?>
83                    <a href="<?php echo esc_url( $post_link ); ?>" rel="bookmark" tabindex="-1" aria-hidden="true">
84                    <?php endif; ?>
85                        <?php if ( $has_featured_image ) : ?>
86                            <?php
87                                the_post_thumbnail(
88                                    'large',
89                                    array(
90                                        'object-fit' => $image_fit,
91                                        'layout'     => 'fill',
92                                        'class'      => 'contain' === $image_fit ? 'image-fit-contain' : 'image-fit-cover',
93                                        'alt'        => trim( wp_strip_all_tags( get_the_title( $post_id ) ) ),
94                                    )
95                                );
96                            ?>
97                        <?php else : ?>
98                            <div class="wp-block-newspack-blocks-carousel__placeholder"></div>
99                        <?php endif; ?>
100                    <?php if ( $post_link ) : ?>
101                    </a>
102                    <?php endif; ?>
103                </figure>
104
105                <?php if ( ! empty( $sponsors ) || $attributes['showCategory'] || $attributes['showTitle'] || $show_author || $show_date || $show_caption || $show_credit ) : ?>
106                    <div class="entry-wrapper">
107                        <?php if ( ! empty( $sponsors ) || $attributes['showCategory'] ) : ?>
108                            <div class="cat-links <?php if ( ! empty( $sponsors ) ) : ?>sponsor-label<?php endif; // phpcs:ignore Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace ?>">
109                                <?php if ( ! empty( $sponsors ) ) : ?>
110                                    <span class="flag">
111                                        <?php echo esc_html( Newspack_Blocks::get_sponsor_label( $sponsors ) ); ?>
112                                    </span>
113                                    <?php
114                                endif;
115
116                                if ( $attributes['showCategory'] && ( empty( $sponsors ) || Newspack_Blocks::newspack_display_sponsors_and_categories( $sponsors ) ) ) :
117                                    echo wp_kses_post( newspack_blocks_format_categories( $post_id ) );
118                                endif;
119                                ?>
120                                </div>
121                            <?php
122                        endif;
123
124                        if ( $attributes['showTitle'] ) {
125                            the_title( '<h3 class="entry-title"><a href="' . esc_url( $post_link ) . '" rel="bookmark">', '</a></h3>' );
126                        }
127                        ?>
128
129                        <div class="entry-meta">
130                            <?php
131                            if ( ! empty( $sponsors ) ) :
132                                $sponsor_classes = [ 'entry-sponsors' ];
133                                if ( Newspack_Blocks::newspack_display_sponsors_and_authors( $sponsors ) ) {
134                                    $sponsor_classes[] = 'plus-author';
135                                }
136                                ?>
137                                <span class="<?php echo esc_attr( implode( ' ', $sponsor_classes ) ); ?>">
138                                    <?php
139                                    $logos = Newspack_Blocks::get_sponsor_logos( $sponsors );
140                                    if ( ! empty( $logos ) ) :
141                                        ?>
142                                    <span class="sponsor-logos">
143                                        <?php
144                                        foreach ( $logos as $logo ) {
145                                            if ( '' !== $logo['url'] ) {
146                                                echo '<a href="' . esc_url( $logo['url'] ) . '" target="_blank">';
147                                            }
148                                            echo '<img src="' . esc_url( $logo['src'] ) . '" alt="' . esc_attr( $logo['alt'] ) . '" width="' . esc_attr( $logo['width'] ) . '" height="' . esc_attr( $logo['height'] ) . '">';
149                                            if ( '' !== $logo['url'] ) {
150                                                echo '</a>';
151                                            }
152                                        }
153                                        ?>
154                                    </span>
155                                    <?php endif; ?>
156
157                                    <span class="byline sponsor-byline">
158                                        <?php
159                                        $bylines = Newspack_Blocks::get_sponsor_byline( $sponsors );
160                                        echo esc_html( $bylines[0]['byline'] ) . ' ';
161                                        foreach ( $bylines as $byline ) {
162                                            echo '<span class="author">';
163                                            if ( '' !== $byline['url'] ) {
164                                                echo '<a target="_blank" href="' . esc_url( $byline['url'] ) . '">';
165                                            }
166                                            echo esc_html( $byline['name'] );
167                                            if ( '' !== $byline['url'] ) {
168                                                echo '</a>';
169                                            }
170                                            echo '</span>' . esc_html( $byline['sep'] );
171                                        }
172                                        ?>
173                                    </span>
174                                </span><!-- .entry-sponsors -->
175                                <?php
176                            endif;
177
178                            if ( $show_author && ( empty( $sponsors ) || Newspack_Blocks::newspack_display_sponsors_and_authors( $sponsors ) ) ) :
179                                if ( $attributes['showAvatar'] ) :
180                                    echo wp_kses(
181                                        newspack_blocks_format_avatars( $authors ),
182                                        Newspack_Blocks::get_sanitized_image_attributes()
183                                    );
184                                endif;
185                                ?>
186                                <span class="byline">
187                                    <?php echo wp_kses_post( newspack_blocks_format_byline( $authors ) ); ?>
188                                </span><!-- .author-name -->
189                                <?php
190                            endif;
191                            if ( $show_date ) :
192                                printf(
193                                    '<time class="entry-date published" datetime="%1$s">%2$s</time>',
194                                    esc_attr( get_the_date( DATE_W3C ) ),
195                                    esc_html( get_the_date() )
196                                );
197                            endif;
198                            if ( $show_caption || $show_credit ) :
199                                $full_caption = Newspack_Blocks::get_image_caption( get_post_thumbnail_id(), $show_caption, $show_credit );
200                                if ( $full_caption ) :
201                                    ?>
202                                    <div class="entry-caption">
203                                        <?php echo wp_kses_post( $full_caption ); ?>
204                                    <?php
205                                endif;
206                            endif;
207                            ?>
208                        </div><!-- .entry-meta -->
209                    </div><!-- .entry-wrapper -->
210                <?php endif; ?>
211            </article>
212            <?php
213        endwhile;
214        endif;
215        wp_reset_postdata();
216    $slides  = ob_get_clean();
217    $buttons = array();
218    for ( $x = 0; $x < $counter; $x++ ) {
219        $aria_label = sprintf(
220            /* translators: %d: Slide number. */
221            __( 'Go to slide %d', 'jetpack-mu-wpcom' ),
222            absint( $x + 1 )
223        );
224        $buttons[] = sprintf(
225            '<button option="%d" class="swiper-pagination-bullet" aria-label="%s" %s></button>',
226            absint( $x ),
227            esc_attr( $aria_label ),
228            0 === $x ? 'selected' : ''
229        );
230    }
231
232    $slides_per_view = absint( $attributes['slidesPerView'] ?? 1 );
233    $aspect_ratio    = floatval( $attributes['aspectRatio'] ?? 0.75 );
234
235    $selector    = sprintf(
236        '<div class="swiper-pagination-bullets" %1$s>%2$s</div>',
237        $attributes['hideControls'] ? 'aria-hidden="true"' : '',
238        implode( '', $buttons )
239    );
240    $navigation  = 1 === $counter ? '' : sprintf(
241        '<button class="swiper-button swiper-button-prev" aria-label="%1$s" %3$s></button><button class="swiper-button swiper-button-next" aria-label="%2$s" %3$s></button>',
242        esc_attr__( 'Previous Slide', 'jetpack-mu-wpcom' ),
243        esc_attr__( 'Next Slide', 'jetpack-mu-wpcom' ),
244        $attributes['hideControls'] ? 'aria-hidden="true"' : ''
245    );
246    $carousel    = sprintf(
247        '<div class="swiper"><div class="swiper-wrapper">%s</div>%s</div>',
248        $slides,
249        $navigation
250    );
251    $autoplay_ui = $autoplay ? newspack_blocks_carousel_block_autoplay_ui( $newspack_blocks_carousel_id ) : '';
252
253    $data_attributes = [
254        'data-current-post-id=' . $post_id,
255        'data-slides-per-view=' . esc_attr( $slides_per_view ),
256        'data-slide-count=' . $counter,
257        'data-aspect-ratio=' . esc_attr( $aspect_ratio ),
258    ];
259
260    if ( $autoplay ) {
261        $data_attributes[] = 'data-autoplay=1';
262        $data_attributes[] = sprintf( 'data-autoplay_delay=%s', esc_attr( $delay ) );
263    }
264    Newspack_Blocks::enqueue_view_assets( 'carousel' );
265    if ( 1 === $counter ) {
266        $selector = '';
267    }
268    return sprintf(
269        '<div class="%1$s" id="wp-block-newspack-carousel__%2$d" %3$s>%4$s%5$s%6$s</div>',
270        esc_attr( $classes ),
271        absint( $newspack_blocks_carousel_id ),
272        esc_attr( implode( ' ', $data_attributes ) ),
273        $autoplay_ui,
274        $carousel,
275        $selector
276    );
277}
278
279/**
280 * Generate autoplay play/pause UI.
281 *
282 * @return string Autoplay UI markup.
283 */
284function newspack_blocks_carousel_block_autoplay_ui() {
285    return sprintf(
286        '<button aria-label="%s" class="swiper-button swiper-button-pause"></button><button aria-label="%s" class="swiper-button swiper-button-play"></button>',
287        esc_attr__( 'Pause Slideshow', 'jetpack-mu-wpcom' ),
288        esc_attr__( 'Play Slideshow', 'jetpack-mu-wpcom' )
289    );
290}
291
292/**
293 * Registers the `newspack-blocks/carousel` block on server.
294 */
295function newspack_blocks_register_carousel() {
296    register_block_type(
297        apply_filters( 'newspack_blocks_block_name', 'newspack-blocks/carousel' ),
298        apply_filters(
299            'newspack_blocks_block_args',
300            array(
301                'attributes'      => array(
302                    'className'        => array(
303                        'type' => 'string',
304                    ),
305                    'postsToShow'      => array(
306                        'type'    => 'integer',
307                        'default' => 3,
308                    ),
309                    'authors'          => array(
310                        'type'    => 'array',
311                        'default' => array(),
312                        'items'   => array(
313                            'type' => 'integer',
314                        ),
315                    ),
316                    'categories'       => array(
317                        'type'    => 'array',
318                        'default' => array(),
319                        'items'   => array(
320                            'type' => 'integer',
321                        ),
322                    ),
323                    'tags'             => array(
324                        'type'    => 'array',
325                        'default' => array(),
326                        'items'   => array(
327                            'type' => 'integer',
328                        ),
329                    ),
330                    'customTaxonomies' => array(
331                        'type'    => 'array',
332                        'default' => array(),
333                        'items'   => array(
334                            'type'       => 'object',
335                            'properties' => array(
336                                'slug'  => array(
337                                    'type' => 'string',
338                                ),
339                                'terms' => array(
340                                    'type'  => 'array',
341                                    'items' => array(
342                                        'type' => 'integer',
343                                    ),
344                                ),
345                            ),
346                        ),
347                    ),
348                    'autoplay'         => array(
349                        'type'    => 'boolean',
350                        'default' => false,
351                    ),
352                    'delay'            => array(
353                        'type'    => 'integer',
354                        'default' => 5,
355                    ),
356                    'showAuthor'       => array(
357                        'type'    => 'boolean',
358                        'default' => true,
359                    ),
360                    'showAvatar'       => array(
361                        'type'    => 'boolean',
362                        'default' => true,
363                    ),
364                    'showCaption'      => array(
365                        'type'    => 'boolean',
366                        'default' => false,
367                    ),
368                    'showCredit'       => array(
369                        'type'    => 'boolean',
370                        'default' => false,
371                    ),
372                    'showCategory'     => array(
373                        'type'    => 'boolean',
374                        'default' => false,
375                    ),
376                    'showDate'         => array(
377                        'type'    => 'boolean',
378                        'default' => true,
379                    ),
380                    'imageFit'         => array(
381                        'type'    => 'string',
382                        'default' => 'cover',
383                    ),
384                    'showTitle'        => array(
385                        'type'    => 'boolean',
386                        'default' => true,
387                    ),
388                    'slidesPerView'    => array(
389                        'type'    => 'number',
390                        'default' => 1,
391                    ),
392                    'hideControls'     => array(
393                        'type'    => 'boolean',
394                        'default' => false,
395                    ),
396                    'aspectRatio'      => array(
397                        'type'    => 'number',
398                        'default' => 0.75,
399                    ),
400                ),
401                'render_callback' => 'newspack_blocks_render_block_carousel',
402                'supports'        => [],
403            ),
404            'carousel'
405        )
406    );
407}
408add_action( 'init', 'newspack_blocks_register_carousel' );