PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.2.4
Jetpack – WP Security, Backup, Speed, & Growth v13.2.4
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / theme-tools / featured-content.php
jetpack / modules / theme-tools Last commit date
compat 2 years ago content-options 2 years ago js 6 years ago responsive-videos 3 years ago site-logo 3 years ago social-menu 2 years ago content-options.php 2 years ago devicepx.php 5 years ago featured-content.php 3 years ago infinite-scroll.php 4 years ago random-redirect.php 3 years ago responsive-videos.php 2 years ago site-breadcrumbs.php 3 years ago site-logo.php 4 years ago social-links.php 3 years ago social-menu.php 4 years ago
featured-content.php
771 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Theme Tools: functions for Featured Content enhancements.
4 *
5 * @package automattic/jetpack
6 */
7
8 use Automattic\Jetpack\Constants;
9
10 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
11
12 if ( ! class_exists( 'Featured_Content' ) && isset( $GLOBALS['pagenow'] ) && 'plugins.php' !== $GLOBALS['pagenow'] ) {
13
14 /**
15 * Featured Content.
16 *
17 * This module will allow users to define a subset of posts to be displayed in a
18 * theme-designated featured content area.
19 *
20 * This feature will only be activated for themes that declare that they support
21 * it. This can be done by adding code similar to the following during the
22 * "after_setup_theme" action:
23 *
24 * add_theme_support( 'featured-content', array(
25 * 'filter' => 'mytheme_get_featured_content',
26 * 'max_posts' => 20,
27 * 'post_types' => array( 'post', 'page' ),
28 * ) );
29 *
30 * For maximum compatibility with different methods of posting users will
31 * designate a featured post tag to associate posts with. Since this tag now has
32 * special meaning beyond that of a normal tags, users will have the ability to
33 * hide it from the front-end of their site.
34 */
35 class Featured_Content {
36
37 /**
38 * The maximum number of posts that a Featured Content area can contain. We
39 * define a default value here but themes can override this by defining a
40 * "max_posts" entry in the second parameter passed in the call to
41 * add_theme_support( 'featured-content' ).
42 *
43 * @see Featured_Content::init()
44 * @var int
45 */
46 public static $max_posts = 15;
47
48 /**
49 * The registered post types supported by Featured Content. Themes can add
50 * Featured Content support for registered post types by defining a
51 * 'post_types' argument (string|array) in the call to
52 * add_theme_support( 'featured-content' ).
53 *
54 * @see Featured_Content::init()
55 * @var array
56 */
57 public static $post_types = array( 'post' );
58
59 /**
60 * The tag that is used to mark featured content. Users can define
61 * a custom tag name that will be stored in this variable.
62 *
63 * @see Featured_Content::hide_featured_term
64 * @var string
65 */
66 public static $tag;
67
68 /**
69 * Instantiate.
70 *
71 * All custom functionality will be hooked into the "init" action.
72 */
73 public static function setup() {
74 add_action( 'init', array( __CLASS__, 'init' ), 30 );
75 }
76
77 /**
78 * Conditionally hook into WordPress.
79 *
80 * Themes must declare that they support this module by adding
81 * add_theme_support( 'featured-content' ); during after_setup_theme.
82 *
83 * If no theme support is found there is no need to hook into WordPress. We'll
84 * just return early instead.
85 *
86 * @uses Featured_Content::$max_posts
87 */
88 public static function init() {
89 $theme_support = get_theme_support( 'featured-content' );
90
91 // Return early if theme does not support featured content.
92 if ( ! $theme_support ) {
93 return;
94 }
95
96 /*
97 * An array of named arguments must be passed as the second parameter
98 * of add_theme_support().
99 */
100 if ( ! isset( $theme_support[0] ) ) {
101 return;
102 }
103
104 if ( isset( $theme_support[0]['featured_content_filter'] ) ) {
105 $theme_support[0]['filter'] = $theme_support[0]['featured_content_filter'];
106 unset( $theme_support[0]['featured_content_filter'] );
107 }
108
109 // Return early if "filter" has not been defined.
110 if ( ! isset( $theme_support[0]['filter'] ) ) {
111 return;
112 }
113
114 // Theme can override the number of max posts.
115 if ( isset( $theme_support[0]['max_posts'] ) ) {
116 self::$max_posts = absint( $theme_support[0]['max_posts'] );
117 }
118
119 add_filter( $theme_support[0]['filter'], array( __CLASS__, 'get_featured_posts' ) );
120 if ( ! wp_is_block_theme() ) {
121 add_action( 'customize_register', array( __CLASS__, 'customize_register' ), 9 );
122 }
123 add_action( 'admin_init', array( __CLASS__, 'register_setting' ) );
124 add_action( 'save_post', array( __CLASS__, 'delete_transient' ) );
125 add_action( 'delete_post_tag', array( __CLASS__, 'delete_post_tag' ) );
126 add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
127 add_action( 'pre_get_posts', array( __CLASS__, 'pre_get_posts' ) );
128 add_action( 'switch_theme', array( __CLASS__, 'switch_theme' ) );
129 add_action( 'switch_theme', array( __CLASS__, 'delete_transient' ) );
130 add_action( 'wp_loaded', array( __CLASS__, 'wp_loaded' ) );
131 add_action( 'update_option_featured-content', array( __CLASS__, 'flush_post_tag_cache' ), 10, 2 );
132 add_action( 'delete_option_featured-content', array( __CLASS__, 'flush_post_tag_cache' ), 10, 2 );
133 add_action( 'split_shared_term', array( __CLASS__, 'jetpack_update_featured_content_for_split_terms', 10, 4 ) );
134
135 if ( isset( $theme_support[0]['additional_post_types'] ) ) {
136 $theme_support[0]['post_types'] = array_merge( array( 'post' ), (array) $theme_support[0]['additional_post_types'] );
137 unset( $theme_support[0]['additional_post_types'] );
138 }
139
140 // Themes can allow Featured Content pages.
141 if ( isset( $theme_support[0]['post_types'] ) ) {
142 self::$post_types = array_merge( self::$post_types, (array) $theme_support[0]['post_types'] );
143 self::$post_types = array_unique( self::$post_types );
144
145 // register post_tag support for each post type.
146 foreach ( self::$post_types as $post_type ) {
147 register_taxonomy_for_object_type( 'post_tag', $post_type );
148 }
149 }
150 }
151
152 /**
153 * Hide "featured" tag from the front-end.
154 *
155 * Has to run on wp_loaded so that the preview filters of the customizer
156 * have a chance to alter the value.
157 */
158 public static function wp_loaded() {
159 if ( self::get_setting( 'hide-tag' ) ) {
160 $settings = self::get_setting();
161
162 // This is done before setting filters for get_terms in order to avoid an infinite filter loop.
163 self::$tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
164
165 add_filter( 'get_terms', array( __CLASS__, 'hide_featured_term' ), 10, 3 );
166 add_filter( 'get_the_terms', array( __CLASS__, 'hide_the_featured_term' ), 10, 3 );
167 }
168 }
169
170 /**
171 * Get featured posts
172 *
173 * This method is not intended to be called directly. Theme developers should
174 * place a filter directly in their theme and then pass its name as a value of
175 * the "filter" key in the array passed as the $args parameter during the call
176 * to: add_theme_support( 'featured-content', $args ).
177 *
178 * @uses Featured_Content::get_featured_post_ids()
179 *
180 * @return array
181 */
182 public static function get_featured_posts() {
183 $post_ids = self::get_featured_post_ids();
184
185 // No need to query if there is are no featured posts.
186 if ( empty( $post_ids ) ) {
187 return array();
188 }
189
190 $featured_posts = get_posts(
191 array(
192 'include' => $post_ids,
193 'posts_per_page' => count( $post_ids ), // phpcs:ignore WordPress.WP.PostsPerPage.posts_per_page_posts_per_page
194 'post_type' => self::$post_types,
195 'suppress_filters' => false,
196 )
197 );
198
199 return $featured_posts;
200 }
201
202 /**
203 * Get featured post IDs
204 *
205 * This function will return the an array containing the post IDs of all
206 * featured posts.
207 *
208 * Sets the "featured_content_ids" transient.
209 *
210 * @return array Array of post IDs.
211 */
212 public static function get_featured_post_ids() {
213 // Return array of cached results if they exist.
214 $featured_ids = get_transient( 'featured_content_ids' );
215 if ( ! empty( $featured_ids ) ) {
216 return array_map(
217 'absint',
218 /**
219 * Filter the list of Featured Posts IDs.
220 *
221 * @module theme-tools
222 *
223 * @since 2.7.0
224 *
225 * @param array $featured_ids Array of post IDs.
226 */
227 apply_filters( 'featured_content_post_ids', (array) $featured_ids )
228 );
229 }
230
231 $settings = self::get_setting();
232
233 // Return empty array if no tag name is set.
234 $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
235 if ( ! $term ) {
236 $term = get_term_by( 'id', $settings['tag-id'], 'post_tag' );
237 }
238 if ( $term ) {
239 $tag = $term->term_id;
240 } else {
241 /** This action is documented in modules/theme-tools/featured-content.php */
242 return apply_filters( 'featured_content_post_ids', array() );
243 }
244
245 // Back compat for installs that have the quantity option still set.
246 $quantity = isset( $settings['quantity'] ) ? $settings['quantity'] : self::$max_posts;
247
248 // Query for featured posts.
249 $featured = get_posts(
250 array(
251 'numberposts' => $quantity,
252 'post_type' => self::$post_types,
253 'suppress_filters' => false,
254 'tax_query' => array(
255 array(
256 'field' => 'term_id',
257 'taxonomy' => 'post_tag',
258 'terms' => $tag,
259 ),
260 ),
261 )
262 );
263
264 // Return empty array if no featured content exists.
265 if ( ! $featured ) {
266 /** This action is documented in modules/theme-tools/featured-content.php */
267 return apply_filters( 'featured_content_post_ids', array() );
268 }
269
270 // Ensure correct format before save/return.
271 $featured_ids = wp_list_pluck( (array) $featured, 'ID' );
272 $featured_ids = array_map( 'absint', $featured_ids );
273
274 set_transient( 'featured_content_ids', $featured_ids );
275
276 /** This action is documented in modules/theme-tools/featured-content.php */
277 return apply_filters( 'featured_content_post_ids', $featured_ids );
278 }
279
280 /**
281 * Delete Transient.
282 *
283 * Hooks in the "save_post" action.
284 *
285 * @see Featured_Content::validate_settings().
286 */
287 public static function delete_transient() {
288 delete_transient( 'featured_content_ids' );
289 }
290
291 /**
292 * Flush the Post Tag relationships cache.
293 *
294 * Hooks in the "update_option_featured-content" action.
295 *
296 * @param array $prev Previous option data.
297 * @param array $opts New option data.
298 */
299 public static function flush_post_tag_cache( $prev, $opts ) {
300 if ( ! empty( $opts ) && ! empty( $opts['tag-id'] ) ) {
301 $query = new WP_Query(
302 array(
303 'tag_id' => (int) $opts['tag-id'],
304 'posts_per_page' => -1,
305 )
306 );
307 foreach ( $query->posts as $post ) {
308 wp_cache_delete( $post->ID, 'post_tag_relationships' );
309 }
310 }
311 }
312
313 /**
314 * Exclude featured posts from the blog query when the blog is the front-page,
315 * and user has not checked the "Also display tagged posts outside the Featured Content area" checkbox.
316 *
317 * Filter the home page posts, and remove any featured post ID's from it.
318 * Hooked onto the 'pre_get_posts' action, this changes the parameters of the
319 * query before it gets any posts.
320 *
321 * @uses Featured_Content::get_featured_post_ids();
322 * @uses Featured_Content::get_setting();
323 * @param WP_Query $query WP_Query object.
324 * @return WP_Query Possibly modified WP_Query
325 */
326 public static function pre_get_posts( $query ) {
327
328 // Bail if not home or not main query.
329 if ( ! $query->is_home() || ! $query->is_main_query() ) {
330 return;
331 }
332
333 // Bail if the blog page is not the front page.
334 if ( 'posts' !== get_option( 'show_on_front' ) ) {
335 return;
336 }
337
338 $featured = self::get_featured_post_ids();
339
340 // Bail if no featured posts.
341 if ( ! $featured ) {
342 return;
343 }
344
345 $settings = self::get_setting();
346
347 // Bail if the user wants featured posts always displayed.
348 if ( $settings['show-all'] ) {
349 return;
350 }
351
352 // We need to respect post ids already in the blocklist.
353 $post__not_in = $query->get( 'post__not_in' );
354
355 if ( ! empty( $post__not_in ) ) {
356 $featured = array_merge( (array) $post__not_in, $featured );
357 $featured = array_unique( $featured );
358 }
359
360 $query->set( 'post__not_in', $featured );
361 }
362
363 /**
364 * Reset tag option when the saved tag is deleted.
365 *
366 * It's important to mention that the transient needs to be deleted, too.
367 * While it may not be obvious by looking at the function alone, the transient
368 * is deleted by Featured_Content::validate_settings().
369 *
370 * Hooks in the "delete_post_tag" action.
371 *
372 * @see Featured_Content::validate_settings().
373 *
374 * @param int $tag_id The term_id of the tag that has been deleted.
375 * @return void
376 */
377 public static function delete_post_tag( $tag_id ) {
378 $settings = self::get_setting();
379
380 if ( empty( $settings['tag-id'] ) || $tag_id != $settings['tag-id'] ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual
381 return;
382 }
383
384 $settings['tag-id'] = 0;
385 $settings = self::validate_settings( $settings );
386 update_option( 'featured-content', $settings );
387 }
388
389 /**
390 * Hide featured tag from displaying when global terms are queried from
391 * the front-end.
392 *
393 * Hooks into the "get_terms" filter.
394 *
395 * @uses Featured_Content::get_setting()
396 *
397 * @param array $terms A list of term objects. This is the return value of get_terms().
398 * @param array $taxonomies An array of taxonomy slugs.
399 * @param array $args Array of get_terms() arguments.
400 * @return array $terms
401 */
402 public static function hide_featured_term( $terms, $taxonomies, $args ) {
403
404 // This filter is only appropriate on the front-end.
405 if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) {
406 return $terms;
407 }
408
409 // WordPress defines the parameter as `array`, but it passes null if `get_terms( $args )` was called
410 // without a 'taxonomy' in $args.
411 if ( ! is_array( $taxonomies ) ) {
412 return $terms;
413 }
414
415 // We only want to hide the featured tag.
416 if ( ! in_array( 'post_tag', $taxonomies, true ) ) {
417 return $terms;
418 }
419
420 // Bail if no terms were returned.
421 if ( empty( $terms ) ) {
422 return $terms;
423 }
424
425 // Bail if term objects are unavailable.
426 if ( 'all' !== $args['fields'] ) {
427 return $terms;
428 }
429
430 $settings = self::get_setting();
431
432 if ( false !== self::$tag ) {
433 foreach ( $terms as $order => $term ) {
434 if (
435 is_object( $term )
436 && (
437 $settings['tag-id'] === $term->term_id
438 || $settings['tag-name'] === $term->name
439 )
440 ) {
441 unset( $terms[ $order ] );
442 }
443 }
444 }
445
446 return $terms;
447 }
448
449 /**
450 * Hide featured tag from displaying when terms associated with a post object
451 * are queried from the front-end.
452 *
453 * Hooks into the "get_the_terms" filter.
454 *
455 * @uses Featured_Content::get_setting()
456 *
457 * @param array $terms A list of term objects. This is the return value of get_the_terms().
458 * @param int $id The ID field for the post object that terms are associated with.
459 * @param array $taxonomy An array of taxonomy slugs.
460 * @return array $terms
461 */
462 public static function hide_the_featured_term( $terms, $id, $taxonomy ) {
463
464 // This filter is only appropriate on the front-end.
465 if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) {
466 return $terms;
467 }
468
469 // Make sure we are in the correct taxonomy.
470 if ( 'post_tag' !== $taxonomy ) {
471 return $terms;
472 }
473
474 // No terms? Return early!
475 if ( empty( $terms ) ) {
476 return $terms;
477 }
478
479 $settings = self::get_setting();
480 $tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
481
482 if ( false !== $tag ) {
483 foreach ( $terms as $order => $term ) {
484 if ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) {
485 unset( $terms[ $order ] );
486 }
487 }
488 }
489
490 return $terms;
491 }
492
493 /**
494 * Register custom setting on the Settings -> Reading screen.
495 *
496 * @uses Featured_Content::render_form()
497 * @uses Featured_Content::validate_settings()
498 *
499 * @return void
500 */
501 public static function register_setting() {
502 add_settings_field( 'featured-content', __( 'Featured Content', 'jetpack' ), array( __CLASS__, 'render_form' ), 'reading' );
503
504 // Register sanitization callback for the Customizer.
505 register_setting( 'featured-content', 'featured-content', array( __CLASS__, 'validate_settings' ) );
506 }
507
508 /**
509 * Add settings to the Customizer.
510 *
511 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
512 */
513 public static function customize_register( $wp_customize ) {
514 $wp_customize->add_section(
515 'featured_content',
516 array(
517 'title' => esc_html__( 'Featured Content', 'jetpack' ),
518 'description' => sprintf(
519 /* translators: %1$s: Link to 'featured' admin tag view. %2$s: Max number of posts shown by theme in featured content area. */
520 __( 'Easily feature all posts with the <a href="%1$s">"featured" tag</a> or a tag of your choice. Your theme supports up to %2$s posts in its featured content area.', 'jetpack' ),
521 admin_url( '/edit.php?tag=featured' ),
522 absint( self::$max_posts )
523 ),
524 'priority' => 130,
525 'theme_supports' => 'featured-content',
526 )
527 );
528
529 /*
530 Add Featured Content settings.
531 *
532 * Sanitization callback registered in Featured_Content::validate_settings().
533 * See https://themeshaper.com/2013/04/29/validation-sanitization-in-customizer/comment-page-1/#comment-12374
534 */
535 $wp_customize->add_setting(
536 'featured-content[tag-name]',
537 array(
538 'type' => 'option',
539 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
540 )
541 );
542 $wp_customize->add_setting(
543 'featured-content[hide-tag]',
544 array(
545 'default' => true,
546 'type' => 'option',
547 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
548 )
549 );
550 $wp_customize->add_setting(
551 'featured-content[show-all]',
552 array(
553 'default' => false,
554 'type' => 'option',
555 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
556 )
557 );
558
559 // Add Featured Content controls.
560 $wp_customize->add_control(
561 'featured-content[tag-name]',
562 array(
563 'label' => esc_html__( 'Tag name', 'jetpack' ),
564 'section' => 'featured_content',
565 'theme_supports' => 'featured-content',
566 'priority' => 20,
567 )
568 );
569 $wp_customize->add_control(
570 'featured-content[hide-tag]',
571 array(
572 'label' => esc_html__( 'Do not display tag in post details and tag clouds.', 'jetpack' ),
573 'section' => 'featured_content',
574 'theme_supports' => 'featured-content',
575 'type' => 'checkbox',
576 'priority' => 30,
577 )
578 );
579 $wp_customize->add_control(
580 'featured-content[show-all]',
581 array(
582 'label' => esc_html__( 'Also display tagged posts outside the Featured Content area.', 'jetpack' ),
583 'section' => 'featured_content',
584 'theme_supports' => 'featured-content',
585 'type' => 'checkbox',
586 'priority' => 40,
587 )
588 );
589 }
590
591 /**
592 * Enqueue the tag suggestion script.
593 */
594 public static function enqueue_scripts() {
595 wp_enqueue_script( 'featured-content-suggest', plugins_url( 'js/suggest.js', __FILE__ ), array( 'jquery', 'suggest' ), '20131022', true );
596 }
597
598 /**
599 * Renders all form fields on the Settings -> Reading screen.
600 */
601 public static function render_form() {
602 printf(
603 wp_kses(
604 /* translators: %s: Link to the Featured Content settings in the Customizer. */
605 __( 'The settings for Featured Content have <a href="%s">moved to Appearance &rarr; Customize</a>.', 'jetpack' ),
606 array(
607 'a' => array( 'href' => array() ),
608 )
609 ),
610 esc_url( admin_url( 'customize.php?#accordion-section-featured_content' ) )
611 );
612 }
613
614 /**
615 * Get settings
616 *
617 * Get all settings recognized by this module. This function will return all
618 * settings whether or not they have been stored in the database yet. This
619 * ensures that all keys are available at all times.
620 *
621 * In the event that you only require one setting, you may pass its name as the
622 * first parameter to the function and only that value will be returned.
623 *
624 * @param string $key The key of a recognized setting.
625 * @return mixed Array of all settings by default. A single value if passed as first parameter.
626 */
627 public static function get_setting( $key = 'all' ) {
628 $saved = (array) get_option( 'featured-content' );
629
630 /**
631 * Filter Featured Content's default settings.
632 *
633 * @module theme-tools
634 *
635 * @since 2.7.0
636 *
637 * @param array $args {
638 * Array of Featured Content Settings
639 *
640 * @type int hide-tag Default is 1.
641 * @type int tag-id Default is 0.
642 * @type string tag-name Default is empty.
643 * @type int show-all Default is 0.
644 * }
645 */
646 $defaults = apply_filters(
647 'featured_content_default_settings',
648 array(
649 'hide-tag' => 1,
650 'tag-id' => 0,
651 'tag-name' => '',
652 'show-all' => 0,
653 )
654 );
655
656 $options = wp_parse_args( $saved, $defaults );
657 $options = array_intersect_key( $options, $defaults );
658
659 if ( 'all' !== $key ) {
660 return isset( $options[ $key ] ) ? $options[ $key ] : false;
661 }
662
663 return $options;
664 }
665
666 /**
667 * Validate settings
668 *
669 * Make sure that all user supplied content is in an expected format before
670 * saving to the database. This function will also delete the transient set in
671 * Featured_Content::get_featured_content().
672 *
673 * @uses Featured_Content::delete_transient()
674 *
675 * @param array $input Array of settings input.
676 * @return array $output
677 */
678 public static function validate_settings( $input ) {
679 $output = array();
680
681 if ( empty( $input['tag-name'] ) ) {
682 $output['tag-id'] = 0;
683 } else {
684 $term = get_term_by( 'name', $input['tag-name'], 'post_tag' );
685
686 if ( $term ) {
687 $output['tag-id'] = $term->term_id;
688 } else {
689 $new_tag = wp_create_tag( $input['tag-name'] );
690
691 if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) ) {
692 $output['tag-id'] = $new_tag['term_id'];
693 }
694 }
695
696 $output['tag-name'] = $input['tag-name'];
697 }
698
699 $output['hide-tag'] = isset( $input['hide-tag'] ) && $input['hide-tag'] ? 1 : 0;
700
701 $output['show-all'] = isset( $input['show-all'] ) && $input['show-all'] ? 1 : 0;
702
703 self::delete_transient();
704
705 return $output;
706 }
707
708 /**
709 * Removes the quantity setting from the options array.
710 *
711 * @return void
712 */
713 public static function switch_theme() {
714 $option = (array) get_option( 'featured-content' );
715
716 if ( isset( $option['quantity'] ) ) {
717 unset( $option['quantity'] );
718 update_option( 'featured-content', $option );
719 }
720 }
721
722 /**
723 * Update Featured Content term data as necessary when a shared term is split.
724 *
725 * @param int $old_term_id ID of the formerly shared term.
726 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id.
727 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split.
728 * @param string $taxonomy Taxonomy for the split term.
729 */
730 public static function jetpack_update_featured_content_for_split_terms( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
731 $featured_content_settings = get_option( 'featured-content', array() );
732
733 // Check to see whether the stored tag ID is the one that's just been split.
734 if ( isset( $featured_content_settings['tag-id'] ) && $old_term_id == $featured_content_settings['tag-id'] && 'post_tag' === $taxonomy ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
735 // We have a match, so we swap out the old tag ID for the new one and resave the option.
736 $featured_content_settings['tag-id'] = $new_term_id;
737 update_option( 'featured-content', $featured_content_settings );
738 }
739 }
740 }
741
742 /**
743 * Adds the featured content plugin to the set of files for which action
744 * handlers should be copied when the theme context is loaded by the REST API.
745 *
746 * @param array $copy_dirs Copy paths with actions to be copied.
747 * @return array Copy paths with featured content plugin
748 */
749 function wpcom_rest_api_featured_content_copy_plugin_actions( $copy_dirs ) {
750 $copy_dirs[] = __FILE__;
751 return $copy_dirs;
752 }
753 add_action( 'restapi_theme_action_copy_dirs', 'wpcom_rest_api_featured_content_copy_plugin_actions' );
754
755 /**
756 * Delayed initialization for API Requests.
757 *
758 * @param object $request REST request object.
759 */
760 function wpcom_rest_request_before_callbacks( $request ) {
761 Featured_Content::init();
762 return $request;
763 }
764
765 if ( Constants::is_true( 'IS_WPCOM' ) && Constants::is_true( 'REST_API_REQUEST' ) ) {
766 add_filter( 'rest_request_before_callbacks', 'wpcom_rest_request_before_callbacks' );
767 }
768
769 Featured_Content::setup();
770 }
771