Completed
Push — add/homepage-articles ( 7bb8ee )
by
unknown
58:57 queued 50:32
created

Newspack_Blocks::add_image_sizes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
1
<?php
2
/**
3
 * Newspack blocks functionality
4
 *
5
 * @package Newspack_Blocks
6
 */
7
8
/**
9
 * Newspack blocks functionality
10
 */
11
class Newspack_Blocks {
12
13
	/**
14
	 * Add hooks and filters.
15
	 */
16
	public static function init() {
17
		add_action( 'after_setup_theme', array( __CLASS__, 'add_image_sizes' ) );
18
	}
19
20
	/**
21
	 * Gather dependencies and paths needed for script enqueuing.
22
	 *
23
	 * @param string $script_path Path to the script relative to plugin root.
24
	 *
25
	 * @return array Associative array including dependency array, version, and web path to the script. Returns false if script doesn't exist.
26
	 */
27
	public static function script_enqueue_helper( $script_path ) {
28
		$local_path = NEWSPACK_BLOCKS__PLUGIN_DIR . $script_path;
29
		if ( ! file_exists( $local_path ) ) {
30
			return false;
31
		}
32
33
		$path_info   = pathinfo( $local_path );
34
		$asset_path  = $path_info['dirname'] . '/' . $path_info['filename'] . '.asset.php';
35
		$script_data = file_exists( $asset_path )
36
			? require $asset_path
37
			: array(
38
				'dependencies' => array(),
39
				'version'      => filemtime( $local_path ),
40
			);
41
42
		$script_data['script_path'] = plugins_url( $script_path, __FILE__ );
43
		return $script_data;
44
	}
45
46
	/**
47
	 * Enqueue block scripts and styles for editor.
48
	 */
49
	public static function enqueue_block_editor_assets() {
50
		$script_data = static::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'editor.js' );
51
52
		if ( $script_data ) {
53
			wp_enqueue_script(
54
				'newspack-blocks-editor',
55
				$script_data['script_path'],
56
				$script_data['dependencies'],
57
				$script_data['version'],
58
				true
59
			);
60
			wp_localize_script(
61
				'newspack-blocks-editor',
62
				'newspack_blocks_data',
63
				array(
64
					'patterns'      => self::get_patterns_for_post_type( get_post_type() ),
65
					'_experimental' => self::use_experimental(),
66
				)
67
			);
68
69
			wp_set_script_translations(
70
				'newspack-blocks-editor',
71
				'newspack-blocks',
72
				plugin_dir_path( __FILE__ ) . 'languages'
73
			);
74
		}
75
76
		$editor_style = plugins_url( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'editor.css', __FILE__ );
77
78
		wp_enqueue_style(
79
			'newspack-blocks-editor',
80
			$editor_style,
81
			array(),
82
			NEWSPACK_BLOCKS__VERSION
83
		);
84
	}
85
86
	/**
87
	 * Enqueue block styles stylesheet.
88
	 */
89
	public static function enqueue_block_styles_assets() {
90
		$style_path = NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'block_styles' . ( is_rtl() ? '.rtl' : '' ) . '.css';
91 View Code Duplication
		if ( file_exists( NEWSPACK_BLOCKS__PLUGIN_DIR . $style_path ) ) {
92
			wp_enqueue_style(
93
				'newspack-blocks-block-styles-stylesheet',
94
				plugins_url( $style_path, __FILE__ ),
95
				array(),
96
				NEWSPACK_BLOCKS__VERSION
97
			);
98
		}
99
	}
100
101
	/**
102
	 * Enqueue view scripts and styles for a single block.
103
	 *
104
	 * @param string $type The block's type.
105
	 */
106
	public static function enqueue_view_assets( $type ) {
107
		$style_path = apply_filters(
108
			'newspack_blocks_enqueue_view_assets',
109
			NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . $type . '/view' . ( is_rtl() ? '.rtl' : '' ) . '.css',
110
			$type,
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $type.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
111
			is_rtl()
112
		);
113
114 View Code Duplication
		if ( file_exists( NEWSPACK_BLOCKS__PLUGIN_DIR . $style_path ) ) {
115
			wp_enqueue_style(
116
				"newspack-blocks-{$type}",
117
				plugins_url( $style_path, __FILE__ ),
118
				array(),
119
				NEWSPACK_BLOCKS__VERSION
120
			);
121
		}
122
		if ( static::is_amp() ) {
123
			return;
124
		}
125
		$script_data = static::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . $type . '/view.js' );
126
		if ( $script_data ) {
127
			wp_enqueue_script(
128
				"newspack-blocks-{$type}",
129
				$script_data['script_path'],
130
				$script_data['dependencies'],
131
				$script_data['version'],
132
				true
133
			);
134
		}
135
	}
136
137
	/**
138
	 * Utility to assemble the class for a server-side rendered block.
139
	 *
140
	 * @param string $type The block type.
141
	 * @param array  $attributes Block attributes.
142
	 * @param array  $extra Additional classes to be added to the class list.
143
	 *
144
	 * @return string Class list separated by spaces.
145
	 */
146
	public static function block_classes( $type, $attributes = array(), $extra = array() ) {
147
		$classes = array( "wp-block-newspack-blocks-{$type}" );
148
149
		if ( ! empty( $attributes['align'] ) ) {
150
			$classes[] = 'align' . $attributes['align'];
151
		}
152
		if ( isset( $attributes['className'] ) ) {
153
			array_push( $classes, $attributes['className'] );
154
		}
155
		if ( is_array( $extra ) && ! empty( $extra ) ) {
156
			$classes = array_merge( $classes, $extra );
157
		}
158
159
		return implode( ' ', $classes );
160
	}
161
162
	/**
163
	 * Checks whether the current view is served in AMP context.
164
	 *
165
	 * @return bool True if AMP, false otherwise.
166
	 */
167
	public static function is_amp() {
168
		return ! is_admin() && function_exists( 'is_amp_endpoint' ) && is_amp_endpoint();
169
	}
170
171
	/**
172
	 * Return the most appropriate thumbnail size to display.
173
	 *
174
	 * @param string $orientation The block's orientation settings: landscape|portrait|square.
175
	 *
176
	 * @return string Returns the thumbnail key to use.
177
	 */
178
	public static function image_size_for_orientation( $orientation = 'landscape' ) {
179
		$sizes = array(
180
			'landscape' => array(
181
				'large'  => array(
182
					1200,
183
					900,
184
				),
185
				'medium' => array(
186
					800,
187
					600,
188
				),
189
				'small'  => array(
190
					400,
191
					300,
192
				),
193
				'tiny'   => array(
194
					200,
195
					150,
196
				),
197
			),
198
			'portrait'  => array(
199
				'large'  => array(
200
					900,
201
					1200,
202
				),
203
				'medium' => array(
204
					600,
205
					800,
206
				),
207
				'small'  => array(
208
					300,
209
					400,
210
				),
211
				'tiny'   => array(
212
					150,
213
					200,
214
				),
215
			),
216
			'square'    => array(
217
				'large'  => array(
218
					1200,
219
					1200,
220
				),
221
				'medium' => array(
222
					800,
223
					800,
224
				),
225
				'small'  => array(
226
					400,
227
					400,
228
				),
229
				'tiny'   => array(
230
					200,
231
					200,
232
				),
233
			),
234
		);
235
236
		foreach ( $sizes[ $orientation ] as $key => $dimensions ) {
237
			$attachment = wp_get_attachment_image_src(
238
				get_post_thumbnail_id( get_the_ID() ),
239
				'newspack-article-block-' . $orientation . '-' . $key
240
			);
241
			if ( $dimensions[0] === $attachment[1] && $dimensions[1] === $attachment[2] ) {
242
				return 'newspack-article-block-' . $orientation . '-' . $key;
243
			}
244
		}
245
246
		return 'large';
247
	}
248
249
	/**
250
	 * Registers image sizes required for Newspack Blocks.
251
	 */
252
	public static function add_image_sizes() {
253
		add_image_size( 'newspack-article-block-landscape-large', 1200, 900, true );
254
		add_image_size( 'newspack-article-block-portrait-large', 900, 1200, true );
255
		add_image_size( 'newspack-article-block-square-large', 1200, 1200, true );
256
257
		add_image_size( 'newspack-article-block-landscape-medium', 800, 600, true );
258
		add_image_size( 'newspack-article-block-portrait-medium', 600, 800, true );
259
		add_image_size( 'newspack-article-block-square-medium', 800, 800, true );
260
261
		add_image_size( 'newspack-article-block-landscape-small', 400, 300, true );
262
		add_image_size( 'newspack-article-block-portrait-small', 300, 400, true );
263
		add_image_size( 'newspack-article-block-square-small', 400, 400, true );
264
265
		add_image_size( 'newspack-article-block-landscape-tiny', 200, 150, true );
266
		add_image_size( 'newspack-article-block-portrait-tiny', 150, 200, true );
267
		add_image_size( 'newspack-article-block-square-tiny', 200, 200, true );
268
269
		add_image_size( 'newspack-article-block-uncropped', 1200, 9999, false );
270
	}
271
272
	/**
273
	 * Builds and returns query args based on block attributes.
274
	 *
275
	 * @param array $attributes An array of block attributes.
276
	 *
277
	 * @return array
278
	 */
279
	public static function build_articles_query( $attributes ) {
280
		global $newspack_blocks_post_id;
281
		if ( ! $newspack_blocks_post_id ) {
282
			$newspack_blocks_post_id = array();
283
		}
284
285
		// Get all blocks and gather specificPosts ids of all Homepage Articles blocks.
286
		global $newspack_blocks_all_specific_posts_ids;
287
		if ( ! is_array( $newspack_blocks_all_specific_posts_ids ) ) {
288
			$blocks                                 = parse_blocks( get_the_content() );
289
			$block_name                             = apply_filters( 'newspack_blocks_block_name', 'newspack-blocks/homepage-articles' );
290
			$newspack_blocks_all_specific_posts_ids = array_reduce(
291
				$blocks,
292
				function ( $acc, $block ) use ( $block_name ) {
293
					if (
294
						$block_name === $block['blockName'] &&
295
						isset( $block['attrs']['specificMode'], $block['attrs']['specificPosts'] ) &&
296
						count( $block['attrs']['specificPosts'] )
297
					) {
298
						return array_merge(
299
							$block['attrs']['specificPosts'],
300
							$acc
301
						);
302
					}
303
					return $acc;
304
				},
305
				array()
306
			);
307
		}
308
309
		$authors        = isset( $attributes['authors'] ) ? $attributes['authors'] : array();
310
		$categories     = isset( $attributes['categories'] ) ? $attributes['categories'] : array();
311
		$tags           = isset( $attributes['tags'] ) ? $attributes['tags'] : array();
312
		$tag_exclusions = isset( $attributes['tagExclusions'] ) ? $attributes['tagExclusions'] : array();
313
		$specific_posts = isset( $attributes['specificPosts'] ) ? $attributes['specificPosts'] : array();
314
		$posts_to_show  = intval( $attributes['postsToShow'] );
315
		$specific_mode  = intval( $attributes['specificMode'] );
316
		$args           = array(
317
			'post_status'         => 'publish',
318
			'suppress_filters'    => false,
319
			'ignore_sticky_posts' => true,
320
		);
321
		if ( $specific_mode && $specific_posts ) {
322
			$args['post__in'] = $specific_posts;
323
			$args['orderby']  = 'post__in';
324
		} else {
325
			$args['posts_per_page'] = $posts_to_show;
326
			if ( count( $newspack_blocks_all_specific_posts_ids ) ) {
327
				$args['post__not_in'] = $newspack_blocks_all_specific_posts_ids;
328
			}
329
			$args['post__not_in'] = array_merge(
330
				isset( $args['post__not_in'] ) ? $args['post__not_in'] : array(),
331
				array_keys( $newspack_blocks_post_id ),
332
				get_the_ID() ? array( get_the_ID() ) : array()
333
			);
334
			if ( $authors && count( $authors ) ) {
335
				$args['author__in'] = $authors;
336
			}
337
			if ( $categories && count( $categories ) ) {
338
				$args['category__in'] = $categories;
339
			}
340
			if ( $tags && count( $tags ) ) {
341
				$args['tag__in'] = $tags;
342
			}
343
			if ( $tag_exclusions && count( $tag_exclusions ) ) {
344
				$args['tag__not_in'] = $tag_exclusions;
345
			}
346
		}
347
		return $args;
348
	}
349
350
	/**
351
	 * Loads a template with given data in scope.
352
	 *
353
	 * @param string $template full Path to the template to be included.
354
	 * @return string
355
	 */
356
	public static function template_inc( $template ) {
357
		if ( ! strpos( $template, '.php' ) ) {
358
			$template = $template . '.php';
359
		}
360
		if ( ! is_file( $template ) ) {
361
			return '';
362
		}
363
		ob_start();
364
		include $template;
365
		$contents = ob_get_contents();
366
		ob_end_clean();
367
		return $contents;
368
	}
369
370
	/**
371
	 * Prepare an array of authors, taking presence of CoAuthors Plus into account.
372
	 *
373
	 * @return array Array of WP_User objects.
374
	 */
375
	public static function prepare_authors() {
376
		if ( function_exists( 'coauthors_posts_links' ) && ! empty( get_coauthors() ) ) {
377
			$authors = get_coauthors();
378
			foreach ( $authors as $author ) {
379
				// Check if this is a guest author post type.
380 View Code Duplication
				if ( 'guest-author' === get_post_type( $author->ID ) ) {
381
					// If yes, make sure the author actually has an avatar set; otherwise, coauthors_get_avatar returns a featured image.
382
					if ( get_post_thumbnail_id( $author->ID ) ) {
383
						$author->avatar = coauthors_get_avatar( $author, 48 );
384
					} else {
385
						// If there is no avatar, force it to return the current fallback image.
386
						$author->avatar = get_avatar( ' ' );
387
					}
388
				} else {
389
					$author->avatar = coauthors_get_avatar( $author, 48 );
390
				}
391
				$author->url = get_author_posts_url( $author->ID, $author->user_nicename );
392
			}
393
			return $authors;
394
		}
395
		$id = get_the_author_meta( 'ID' );
396
		return array(
397
			(object) array(
398
				'ID'            => $id,
399
				'avatar'        => get_avatar( $id, 48 ),
400
				'url'           => get_author_posts_url( $id ),
401
				'user_nicename' => get_the_author(),
402
				'display_name'  => get_the_author_meta( 'display_name' ),
403
			),
404
		);
405
	}
406
407
	/**
408
	 * Prepare a list of classes based on assigned tags, categories and post formats.
409
	 *
410
	 * @param string $post_id Post ID.
411
	 * @return string CSS classes.
412
	 */
413
	public static function get_term_classes( $post_id ) {
414
		$classes = array();
415
416
		$tags = get_the_terms( $post_id, 'post_tag' );
417
		if ( ! empty( $tags ) ) {
418
			foreach ( $tags as $tag ) {
419
				$classes[] = 'tag-' . $tag->slug;
420
			}
421
		}
422
423
		$categories = get_the_terms( $post_id, 'category' );
424
		if ( ! empty( $categories ) ) {
425
			foreach ( $categories as $cat ) {
426
				$classes[] = 'category-' . $cat->slug;
427
			}
428
		}
429
430
		$post_format = get_post_format( $post_id );
431
		if ( false !== $post_format ) {
432
			$classes[] = 'format-' . $post_format;
433
		}
434
435
		return implode( ' ', $classes );
436
	}
437
438
	/**
439
	 * Get patterns for post type.
440
	 *
441
	 * @param string $post_type Post type.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $post_type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
442
	 * @return array Array of patterns.
443
	 */
444
	public static function get_patterns_for_post_type( $post_type = null ) {
445
		$patterns    = apply_filters( 'newspack_blocks_patterns', array(), $post_type );
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $post_type.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
446
		$categorized = array();
447
		$clean       = array();
448
		foreach ( $patterns as $pattern ) {
449
			if ( ! isset( $pattern['image'] ) || ! $pattern['image'] ) {
450
				continue;
451
			}
452
			$category = isset( $pattern['category'] ) ? $pattern['category'] : __( 'Common', 'jetpack' );
453
			if ( ! isset( $categorized[ $category ] ) ) {
454
				$categorized[ $category ] = array();
455
			}
456
			$categorized[ $category ][] = $pattern;
457
		}
458
		$categories = array_keys( $categorized );
459
		sort( $categories );
460
		foreach ( $categories as $category ) {
461
			$clean[] = array(
462
				'title' => $category,
463
				'items' => $categorized[ $category ],
464
			);
465
		}
466
		return $clean;
467
	}
468
469
	/**
470
	 * Function to check if plugin is enabled, and if there are sponsors.
471
	 *
472
	 * @param string $id Post ID.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $id not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
473
	 * @param string $scope The scope of sponsers to fetch.
474
	 * @param string $type Post type.
475
	 * @param array  $logo_options Logo Options.
476
	 * @return array Array of sponsors.
477
	 */
478
	public static function get_all_sponsors( $id = null, $scope = 'native', $type = 'post', $logo_options = array() ) {
479
		if ( function_exists( '\Newspack_Sponsors\get_sponsors_for_post' ) ) {
480
			$sponsors = \Newspack_Sponsors\get_all_sponsors( $id, $scope, $type, $logo_options ); // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
481
			if ( $sponsors ) {
482
				return $sponsors;
483
			} else {
484
				return false;
485
			}
486
		}
487
	}
488
489
	/**
490
	 * Function to return sponsor 'flag' from first sponsor.
491
	 *
492
	 * @param string $id Post ID.
493
	 * @return string Sponsor flag label.
494
	 */
495
	public static function get_sponsor_label( $id ) {
496
		$sponsors = self::get_all_sponsors( $id );
497
		if ( ! empty( $sponsors ) ) {
498
			$sponsor_flag = $sponsors[0]['sponsor_flag'];
499
			return $sponsor_flag;
500
		}
501
	}
502
503
	/**
504
	 * Outputs the sponsor byline markup for the theme.
505
	 *
506
	 * @param string $id Post ID.
507
	 * @return array Array of Sponsor byline information.
508
	 */
509
	public static function get_sponsor_byline( $id ) {
510
		$sponsors = self::get_all_sponsors( $id );
511
		if ( ! empty( $sponsors ) ) {
512
			$sponsor_count = count( $sponsors );
513
			$i             = 1;
514
			$sponsor_list  = array();
515
516
			foreach ( $sponsors as $sponsor ) {
517
				$i++;
518
				if ( $sponsor_count === $i ) :
519
					/* translators: separates last two sponsor names; needs a space on either side. */
520
					$sep = esc_html__( ' and ', 'jetpack' );
521
				elseif ( $sponsor_count > $i ) :
522
					/* translators: separates all but the last two sponsor names; needs a space at the end. */
523
					$sep = esc_html__( ', ', 'jetpack' );
524
				else :
525
					$sep = '';
526
				endif;
527
528
				$sponsor_list[] = array(
529
					'byline' => $sponsor['sponsor_byline'],
530
					'url'    => $sponsor['sponsor_url'],
531
					'name'   => $sponsor['sponsor_name'],
532
					'sep'    => $sep,
533
				);
534
			}
535
			return $sponsor_list;
536
		}
537
	}
538
539
	/**
540
	 * Outputs set of sponsor logos with links.
541
	 *
542
	 * @param string $id Post ID.
543
	 */
544
	public static function get_sponsor_logos( $id ) {
545
		$sponsors = self::get_all_sponsors(
546
			$id,
547
			'native',
548
			'post',
549
			array(
550
				'maxwidth'  => 80,
551
				'maxheight' => 40,
552
			)
553
		);
554
		if ( ! empty( $sponsors ) ) {
555
			$sponsor_logos = array();
556
			foreach ( $sponsors as $sponsor ) {
557
				if ( ! empty( $sponsor['sponsor_logo'] ) ) :
558
					$sponsor_logos[] = array(
559
						'url'    => $sponsor['sponsor_url'],
560
						'src'    => esc_url( $sponsor['sponsor_logo']['src'] ),
561
						'width'  => esc_attr( $sponsor['sponsor_logo']['img_width'] ),
562
						'height' => esc_attr( $sponsor['sponsor_logo']['img_height'] ),
563
					);
564
				endif;
565
			}
566
567
			return $sponsor_logos;
568
		}
569
	}
570
571
	/**
572
	 * Whether to use experimental features.
573
	 *
574
	 * @return bool Experimental status.
575
	 */
576
	public static function use_experimental() {
577
		return defined( 'NEWSPACK_BLOCKS_EXPERIMENTAL' ) && NEWSPACK_BLOCKS_EXPERIMENTAL;
578
	}
579
}
580
Newspack_Blocks::init();
581