PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.3.2
Jetpack – WP Security, Backup, Speed, & Growth v12.3.2
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 3 years ago content-options 3 years ago js 6 years ago responsive-videos 3 years ago site-logo 3 years ago social-menu 3 years ago content-options.php 4 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 3 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
769 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 add_action( 'customize_register', array( __CLASS__, 'customize_register' ), 9 );
121 add_action( 'admin_init', array( __CLASS__, 'register_setting' ) );
122 add_action( 'save_post', array( __CLASS__, 'delete_transient' ) );
123 add_action( 'delete_post_tag', array( __CLASS__, 'delete_post_tag' ) );
124 add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
125 add_action( 'pre_get_posts', array( __CLASS__, 'pre_get_posts' ) );
126 add_action( 'switch_theme', array( __CLASS__, 'switch_theme' ) );
127 add_action( 'switch_theme', array( __CLASS__, 'delete_transient' ) );
128 add_action( 'wp_loaded', array( __CLASS__, 'wp_loaded' ) );
129 add_action( 'update_option_featured-content', array( __CLASS__, 'flush_post_tag_cache' ), 10, 2 );
130 add_action( 'delete_option_featured-content', array( __CLASS__, 'flush_post_tag_cache' ), 10, 2 );
131 add_action( 'split_shared_term', array( __CLASS__, 'jetpack_update_featured_content_for_split_terms', 10, 4 ) );
132
133 if ( isset( $theme_support[0]['additional_post_types'] ) ) {
134 $theme_support[0]['post_types'] = array_merge( array( 'post' ), (array) $theme_support[0]['additional_post_types'] );
135 unset( $theme_support[0]['additional_post_types'] );
136 }
137
138 // Themes can allow Featured Content pages.
139 if ( isset( $theme_support[0]['post_types'] ) ) {
140 self::$post_types = array_merge( self::$post_types, (array) $theme_support[0]['post_types'] );
141 self::$post_types = array_unique( self::$post_types );
142
143 // register post_tag support for each post type.
144 foreach ( self::$post_types as $post_type ) {
145 register_taxonomy_for_object_type( 'post_tag', $post_type );
146 }
147 }
148 }
149
150 /**
151 * Hide "featured" tag from the front-end.
152 *
153 * Has to run on wp_loaded so that the preview filters of the customizer
154 * have a chance to alter the value.
155 */
156 public static function wp_loaded() {
157 if ( self::get_setting( 'hide-tag' ) ) {
158 $settings = self::get_setting();
159
160 // This is done before setting filters for get_terms in order to avoid an infinite filter loop.
161 self::$tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
162
163 add_filter( 'get_terms', array( __CLASS__, 'hide_featured_term' ), 10, 3 );
164 add_filter( 'get_the_terms', array( __CLASS__, 'hide_the_featured_term' ), 10, 3 );
165 }
166 }
167
168 /**
169 * Get featured posts
170 *
171 * This method is not intended to be called directly. Theme developers should
172 * place a filter directly in their theme and then pass its name as a value of
173 * the "filter" key in the array passed as the $args parameter during the call
174 * to: add_theme_support( 'featured-content', $args ).
175 *
176 * @uses Featured_Content::get_featured_post_ids()
177 *
178 * @return array
179 */
180 public static function get_featured_posts() {
181 $post_ids = self::get_featured_post_ids();
182
183 // No need to query if there is are no featured posts.
184 if ( empty( $post_ids ) ) {
185 return array();
186 }
187
188 $featured_posts = get_posts(
189 array(
190 'include' => $post_ids,
191 'posts_per_page' => count( $post_ids ), // phpcs:ignore WordPress.WP.PostsPerPage.posts_per_page_posts_per_page
192 'post_type' => self::$post_types,
193 'suppress_filters' => false,
194 )
195 );
196
197 return $featured_posts;
198 }
199
200 /**
201 * Get featured post IDs
202 *
203 * This function will return the an array containing the post IDs of all
204 * featured posts.
205 *
206 * Sets the "featured_content_ids" transient.
207 *
208 * @return array Array of post IDs.
209 */
210 public static function get_featured_post_ids() {
211 // Return array of cached results if they exist.
212 $featured_ids = get_transient( 'featured_content_ids' );
213 if ( ! empty( $featured_ids ) ) {
214 return array_map(
215 'absint',
216 /**
217 * Filter the list of Featured Posts IDs.
218 *
219 * @module theme-tools
220 *
221 * @since 2.7.0
222 *
223 * @param array $featured_ids Array of post IDs.
224 */
225 apply_filters( 'featured_content_post_ids', (array) $featured_ids )
226 );
227 }
228
229 $settings = self::get_setting();
230
231 // Return empty array if no tag name is set.
232 $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
233 if ( ! $term ) {
234 $term = get_term_by( 'id', $settings['tag-id'], 'post_tag' );
235 }
236 if ( $term ) {
237 $tag = $term->term_id;
238 } else {
239 /** This action is documented in modules/theme-tools/featured-content.php */
240 return apply_filters( 'featured_content_post_ids', array() );
241 }
242
243 // Back compat for installs that have the quantity option still set.
244 $quantity = isset( $settings['quantity'] ) ? $settings['quantity'] : self::$max_posts;
245
246 // Query for featured posts.
247 $featured = get_posts(
248 array(
249 'numberposts' => $quantity,
250 'post_type' => self::$post_types,
251 'suppress_filters' => false,
252 'tax_query' => array(
253 array(
254 'field' => 'term_id',
255 'taxonomy' => 'post_tag',
256 'terms' => $tag,
257 ),
258 ),
259 )
260 );
261
262 // Return empty array if no featured content exists.
263 if ( ! $featured ) {
264 /** This action is documented in modules/theme-tools/featured-content.php */
265 return apply_filters( 'featured_content_post_ids', array() );
266 }
267
268 // Ensure correct format before save/return.
269 $featured_ids = wp_list_pluck( (array) $featured, 'ID' );
270 $featured_ids = array_map( 'absint', $featured_ids );
271
272 set_transient( 'featured_content_ids', $featured_ids );
273
274 /** This action is documented in modules/theme-tools/featured-content.php */
275 return apply_filters( 'featured_content_post_ids', $featured_ids );
276 }
277
278 /**
279 * Delete Transient.
280 *
281 * Hooks in the "save_post" action.
282 *
283 * @see Featured_Content::validate_settings().
284 */
285 public static function delete_transient() {
286 delete_transient( 'featured_content_ids' );
287 }
288
289 /**
290 * Flush the Post Tag relationships cache.
291 *
292 * Hooks in the "update_option_featured-content" action.
293 *
294 * @param array $prev Previous option data.
295 * @param array $opts New option data.
296 */
297 public static function flush_post_tag_cache( $prev, $opts ) {
298 if ( ! empty( $opts ) && ! empty( $opts['tag-id'] ) ) {
299 $query = new WP_Query(
300 array(
301 'tag_id' => (int) $opts['tag-id'],
302 'posts_per_page' => -1,
303 )
304 );
305 foreach ( $query->posts as $post ) {
306 wp_cache_delete( $post->ID, 'post_tag_relationships' );
307 }
308 }
309 }
310
311 /**
312 * Exclude featured posts from the blog query when the blog is the front-page,
313 * and user has not checked the "Also display tagged posts outside the Featured Content area" checkbox.
314 *
315 * Filter the home page posts, and remove any featured post ID's from it.
316 * Hooked onto the 'pre_get_posts' action, this changes the parameters of the
317 * query before it gets any posts.
318 *
319 * @uses Featured_Content::get_featured_post_ids();
320 * @uses Featured_Content::get_setting();
321 * @param WP_Query $query WP_Query object.
322 * @return WP_Query Possibly modified WP_Query
323 */
324 public static function pre_get_posts( $query ) {
325
326 // Bail if not home or not main query.
327 if ( ! $query->is_home() || ! $query->is_main_query() ) {
328 return;
329 }
330
331 // Bail if the blog page is not the front page.
332 if ( 'posts' !== get_option( 'show_on_front' ) ) {
333 return;
334 }
335
336 $featured = self::get_featured_post_ids();
337
338 // Bail if no featured posts.
339 if ( ! $featured ) {
340 return;
341 }
342
343 $settings = self::get_setting();
344
345 // Bail if the user wants featured posts always displayed.
346 if ( $settings['show-all'] ) {
347 return;
348 }
349
350 // We need to respect post ids already in the blocklist.
351 $post__not_in = $query->get( 'post__not_in' );
352
353 if ( ! empty( $post__not_in ) ) {
354 $featured = array_merge( (array) $post__not_in, $featured );
355 $featured = array_unique( $featured );
356 }
357
358 $query->set( 'post__not_in', $featured );
359 }
360
361 /**
362 * Reset tag option when the saved tag is deleted.
363 *
364 * It's important to mention that the transient needs to be deleted, too.
365 * While it may not be obvious by looking at the function alone, the transient
366 * is deleted by Featured_Content::validate_settings().
367 *
368 * Hooks in the "delete_post_tag" action.
369 *
370 * @see Featured_Content::validate_settings().
371 *
372 * @param int $tag_id The term_id of the tag that has been deleted.
373 * @return void
374 */
375 public static function delete_post_tag( $tag_id ) {
376 $settings = self::get_setting();
377
378 if ( empty( $settings['tag-id'] ) || $tag_id != $settings['tag-id'] ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual
379 return;
380 }
381
382 $settings['tag-id'] = 0;
383 $settings = self::validate_settings( $settings );
384 update_option( 'featured-content', $settings );
385 }
386
387 /**
388 * Hide featured tag from displaying when global terms are queried from
389 * the front-end.
390 *
391 * Hooks into the "get_terms" filter.
392 *
393 * @uses Featured_Content::get_setting()
394 *
395 * @param array $terms A list of term objects. This is the return value of get_terms().
396 * @param array $taxonomies An array of taxonomy slugs.
397 * @param array $args Array of get_terms() arguments.
398 * @return array $terms
399 */
400 public static function hide_featured_term( $terms, $taxonomies, $args ) {
401
402 // This filter is only appropriate on the front-end.
403 if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) {
404 return $terms;
405 }
406
407 // WordPress defines the parameter as `array`, but it passes null if `get_terms( $args )` was called
408 // without a 'taxonomy' in $args.
409 if ( ! is_array( $taxonomies ) ) {
410 return $terms;
411 }
412
413 // We only want to hide the featured tag.
414 if ( ! in_array( 'post_tag', $taxonomies, true ) ) {
415 return $terms;
416 }
417
418 // Bail if no terms were returned.
419 if ( empty( $terms ) ) {
420 return $terms;
421 }
422
423 // Bail if term objects are unavailable.
424 if ( 'all' !== $args['fields'] ) {
425 return $terms;
426 }
427
428 $settings = self::get_setting();
429
430 if ( false !== self::$tag ) {
431 foreach ( $terms as $order => $term ) {
432 if (
433 is_object( $term )
434 && (
435 $settings['tag-id'] === $term->term_id
436 || $settings['tag-name'] === $term->name
437 )
438 ) {
439 unset( $terms[ $order ] );
440 }
441 }
442 }
443
444 return $terms;
445 }
446
447 /**
448 * Hide featured tag from displaying when terms associated with a post object
449 * are queried from the front-end.
450 *
451 * Hooks into the "get_the_terms" filter.
452 *
453 * @uses Featured_Content::get_setting()
454 *
455 * @param array $terms A list of term objects. This is the return value of get_the_terms().
456 * @param int $id The ID field for the post object that terms are associated with.
457 * @param array $taxonomy An array of taxonomy slugs.
458 * @return array $terms
459 */
460 public static function hide_the_featured_term( $terms, $id, $taxonomy ) {
461
462 // This filter is only appropriate on the front-end.
463 if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ) {
464 return $terms;
465 }
466
467 // Make sure we are in the correct taxonomy.
468 if ( 'post_tag' !== $taxonomy ) {
469 return $terms;
470 }
471
472 // No terms? Return early!
473 if ( empty( $terms ) ) {
474 return $terms;
475 }
476
477 $settings = self::get_setting();
478 $tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' );
479
480 if ( false !== $tag ) {
481 foreach ( $terms as $order => $term ) {
482 if ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) {
483 unset( $terms[ $order ] );
484 }
485 }
486 }
487
488 return $terms;
489 }
490
491 /**
492 * Register custom setting on the Settings -> Reading screen.
493 *
494 * @uses Featured_Content::render_form()
495 * @uses Featured_Content::validate_settings()
496 *
497 * @return void
498 */
499 public static function register_setting() {
500 add_settings_field( 'featured-content', __( 'Featured Content', 'jetpack' ), array( __CLASS__, 'render_form' ), 'reading' );
501
502 // Register sanitization callback for the Customizer.
503 register_setting( 'featured-content', 'featured-content', array( __CLASS__, 'validate_settings' ) );
504 }
505
506 /**
507 * Add settings to the Customizer.
508 *
509 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
510 */
511 public static function customize_register( $wp_customize ) {
512 $wp_customize->add_section(
513 'featured_content',
514 array(
515 'title' => esc_html__( 'Featured Content', 'jetpack' ),
516 'description' => sprintf(
517 /* translators: %1$s: Link to 'featured' admin tag view. %2$s: Max number of posts shown by theme in featured content area. */
518 __( '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' ),
519 admin_url( '/edit.php?tag=featured' ),
520 absint( self::$max_posts )
521 ),
522 'priority' => 130,
523 'theme_supports' => 'featured-content',
524 )
525 );
526
527 /*
528 Add Featured Content settings.
529 *
530 * Sanitization callback registered in Featured_Content::validate_settings().
531 * See https://themeshaper.com/2013/04/29/validation-sanitization-in-customizer/comment-page-1/#comment-12374
532 */
533 $wp_customize->add_setting(
534 'featured-content[tag-name]',
535 array(
536 'type' => 'option',
537 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
538 )
539 );
540 $wp_customize->add_setting(
541 'featured-content[hide-tag]',
542 array(
543 'default' => true,
544 'type' => 'option',
545 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
546 )
547 );
548 $wp_customize->add_setting(
549 'featured-content[show-all]',
550 array(
551 'default' => false,
552 'type' => 'option',
553 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),
554 )
555 );
556
557 // Add Featured Content controls.
558 $wp_customize->add_control(
559 'featured-content[tag-name]',
560 array(
561 'label' => esc_html__( 'Tag name', 'jetpack' ),
562 'section' => 'featured_content',
563 'theme_supports' => 'featured-content',
564 'priority' => 20,
565 )
566 );
567 $wp_customize->add_control(
568 'featured-content[hide-tag]',
569 array(
570 'label' => esc_html__( 'Do not display tag in post details and tag clouds.', 'jetpack' ),
571 'section' => 'featured_content',
572 'theme_supports' => 'featured-content',
573 'type' => 'checkbox',
574 'priority' => 30,
575 )
576 );
577 $wp_customize->add_control(
578 'featured-content[show-all]',
579 array(
580 'label' => esc_html__( 'Also display tagged posts outside the Featured Content area.', 'jetpack' ),
581 'section' => 'featured_content',
582 'theme_supports' => 'featured-content',
583 'type' => 'checkbox',
584 'priority' => 40,
585 )
586 );
587 }
588
589 /**
590 * Enqueue the tag suggestion script.
591 */
592 public static function enqueue_scripts() {
593 wp_enqueue_script( 'featured-content-suggest', plugins_url( 'js/suggest.js', __FILE__ ), array( 'jquery', 'suggest' ), '20131022', true );
594 }
595
596 /**
597 * Renders all form fields on the Settings -> Reading screen.
598 */
599 public static function render_form() {
600 printf(
601 wp_kses(
602 /* translators: %s: Link to the Featured Content settings in the Customizer. */
603 __( 'The settings for Featured Content have <a href="%s">moved to Appearance &rarr; Customize</a>.', 'jetpack' ),
604 array(
605 'a' => array( 'href' => array() ),
606 )
607 ),
608 esc_url( admin_url( 'customize.php?#accordion-section-featured_content' ) )
609 );
610 }
611
612 /**
613 * Get settings
614 *
615 * Get all settings recognized by this module. This function will return all
616 * settings whether or not they have been stored in the database yet. This
617 * ensures that all keys are available at all times.
618 *
619 * In the event that you only require one setting, you may pass its name as the
620 * first parameter to the function and only that value will be returned.
621 *
622 * @param string $key The key of a recognized setting.
623 * @return mixed Array of all settings by default. A single value if passed as first parameter.
624 */
625 public static function get_setting( $key = 'all' ) {
626 $saved = (array) get_option( 'featured-content' );
627
628 /**
629 * Filter Featured Content's default settings.
630 *
631 * @module theme-tools
632 *
633 * @since 2.7.0
634 *
635 * @param array $args {
636 * Array of Featured Content Settings
637 *
638 * @type int hide-tag Default is 1.
639 * @type int tag-id Default is 0.
640 * @type string tag-name Default is empty.
641 * @type int show-all Default is 0.
642 * }
643 */
644 $defaults = apply_filters(
645 'featured_content_default_settings',
646 array(
647 'hide-tag' => 1,
648 'tag-id' => 0,
649 'tag-name' => '',
650 'show-all' => 0,
651 )
652 );
653
654 $options = wp_parse_args( $saved, $defaults );
655 $options = array_intersect_key( $options, $defaults );
656
657 if ( 'all' !== $key ) {
658 return isset( $options[ $key ] ) ? $options[ $key ] : false;
659 }
660
661 return $options;
662 }
663
664 /**
665 * Validate settings
666 *
667 * Make sure that all user supplied content is in an expected format before
668 * saving to the database. This function will also delete the transient set in
669 * Featured_Content::get_featured_content().
670 *
671 * @uses Featured_Content::delete_transient()
672 *
673 * @param array $input Array of settings input.
674 * @return array $output
675 */
676 public static function validate_settings( $input ) {
677 $output = array();
678
679 if ( empty( $input['tag-name'] ) ) {
680 $output['tag-id'] = 0;
681 } else {
682 $term = get_term_by( 'name', $input['tag-name'], 'post_tag' );
683
684 if ( $term ) {
685 $output['tag-id'] = $term->term_id;
686 } else {
687 $new_tag = wp_create_tag( $input['tag-name'] );
688
689 if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) ) {
690 $output['tag-id'] = $new_tag['term_id'];
691 }
692 }
693
694 $output['tag-name'] = $input['tag-name'];
695 }
696
697 $output['hide-tag'] = isset( $input['hide-tag'] ) && $input['hide-tag'] ? 1 : 0;
698
699 $output['show-all'] = isset( $input['show-all'] ) && $input['show-all'] ? 1 : 0;
700
701 self::delete_transient();
702
703 return $output;
704 }
705
706 /**
707 * Removes the quantity setting from the options array.
708 *
709 * @return void
710 */
711 public static function switch_theme() {
712 $option = (array) get_option( 'featured-content' );
713
714 if ( isset( $option['quantity'] ) ) {
715 unset( $option['quantity'] );
716 update_option( 'featured-content', $option );
717 }
718 }
719
720 /**
721 * Update Featured Content term data as necessary when a shared term is split.
722 *
723 * @param int $old_term_id ID of the formerly shared term.
724 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id.
725 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split.
726 * @param string $taxonomy Taxonomy for the split term.
727 */
728 public static function jetpack_update_featured_content_for_split_terms( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
729 $featured_content_settings = get_option( 'featured-content', array() );
730
731 // Check to see whether the stored tag ID is the one that's just been split.
732 if ( isset( $featured_content_settings['tag-id'] ) && $old_term_id == $featured_content_settings['tag-id'] && 'post_tag' === $taxonomy ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
733 // We have a match, so we swap out the old tag ID for the new one and resave the option.
734 $featured_content_settings['tag-id'] = $new_term_id;
735 update_option( 'featured-content', $featured_content_settings );
736 }
737 }
738 }
739
740 /**
741 * Adds the featured content plugin to the set of files for which action
742 * handlers should be copied when the theme context is loaded by the REST API.
743 *
744 * @param array $copy_dirs Copy paths with actions to be copied.
745 * @return array Copy paths with featured content plugin
746 */
747 function wpcom_rest_api_featured_content_copy_plugin_actions( $copy_dirs ) {
748 $copy_dirs[] = __FILE__;
749 return $copy_dirs;
750 }
751 add_action( 'restapi_theme_action_copy_dirs', 'wpcom_rest_api_featured_content_copy_plugin_actions' );
752
753 /**
754 * Delayed initialization for API Requests.
755 *
756 * @param object $request REST request object.
757 */
758 function wpcom_rest_request_before_callbacks( $request ) {
759 Featured_Content::init();
760 return $request;
761 }
762
763 if ( Constants::is_true( 'IS_WPCOM' ) && Constants::is_true( 'REST_API_REQUEST' ) ) {
764 add_filter( 'rest_request_before_callbacks', 'wpcom_rest_request_before_callbacks' );
765 }
766
767 Featured_Content::setup();
768 }
769