Featured_Content

Featured Content.

Defined (1)

The class is defined in the following location(s).

/modules/theme-tools/featured-content.php  
  1. class Featured_Content { 
  2.  
  3. /** 
  4. * The maximum number of posts that a Featured Content area can contain. We 
  5. * define a default value here but themes can override this by defining a 
  6. * "max_posts" entry in the second parameter passed in the call to 
  7. * add_theme_support( 'featured-content' ). 
  8. * @see Featured_Content::init() 
  9. */ 
  10. public static $max_posts = 15; 
  11.  
  12. /** 
  13. * The registered post types supported by Featured Content. Themes can add 
  14. * Featured Content support for registered post types by defining a 
  15. * 'post_types' argument (string|array) in the call to 
  16. * add_theme_support( 'featured-content' ). 
  17. * @see Featured_Content::init() 
  18. */ 
  19. public static $post_types = array( 'post' ); 
  20.  
  21. /** 
  22. * Instantiate. 
  23. * All custom functionality will be hooked into the "init" action. 
  24. */ 
  25. public static function setup() { 
  26. add_action( 'init', array( __CLASS__, 'init' ), 30 ); 
  27.  
  28. /** 
  29. * Conditionally hook into WordPress. 
  30. * Themes must declare that they support this module by adding 
  31. * add_theme_support( 'featured-content' ); during after_setup_theme. 
  32. * If no theme support is found there is no need to hook into WordPress. We'll 
  33. * just return early instead. 
  34. * @uses Featured_Content::$max_posts 
  35. */ 
  36. public static function init() { 
  37. $theme_support = get_theme_support( 'featured-content' ); 
  38.  
  39. // Return early if theme does not support featured content. 
  40. if ( ! $theme_support ) { 
  41. return; 
  42.  
  43. /** 
  44. * An array of named arguments must be passed as the second parameter 
  45. * of add_theme_support(). 
  46. */ 
  47. if ( ! isset( $theme_support[0] ) ) { 
  48. return; 
  49.  
  50. if ( isset( $theme_support[0]['featured_content_filter'] ) ) { 
  51. $theme_support[0]['filter'] = $theme_support[0]['featured_content_filter']; 
  52. unset( $theme_support[0]['featured_content_filter'] ); 
  53.  
  54. // Return early if "filter" has not been defined. 
  55. if ( ! isset( $theme_support[0]['filter'] ) ) { 
  56. return; 
  57.  
  58. // Theme can override the number of max posts. 
  59. if ( isset( $theme_support[0]['max_posts'] ) ) { 
  60. self::$max_posts = absint( $theme_support[0]['max_posts'] ); 
  61.  
  62. add_filter( $theme_support[0]['filter'], array( __CLASS__, 'get_featured_posts' ) ); 
  63. add_action( 'customize_register', array( __CLASS__, 'customize_register' ), 9 ); 
  64. add_action( 'admin_init', array( __CLASS__, 'register_setting' ) ); 
  65. add_action( 'save_post', array( __CLASS__, 'delete_transient' ) ); 
  66. add_action( 'delete_post_tag', array( __CLASS__, 'delete_post_tag' ) ); 
  67. add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) ); 
  68. add_action( 'pre_get_posts', array( __CLASS__, 'pre_get_posts' ) ); 
  69. add_action( 'switch_theme', array( __CLASS__, 'switch_theme' ) ); 
  70. add_action( 'switch_theme', array( __CLASS__, 'delete_transient' ) ); 
  71. add_action( 'wp_loaded', array( __CLASS__, 'wp_loaded' ) ); 
  72. add_action( 'split_shared_term', array( __CLASS__, 'jetpack_update_featured_content_for_split_terms', 10, 4 ) ); 
  73.  
  74.  
  75. if ( isset( $theme_support[0]['additional_post_types'] ) ) { 
  76. $theme_support[0]['post_types'] = array_merge( array( 'post' ), (array) $theme_support[0]['additional_post_types'] ); 
  77. unset( $theme_support[0]['additional_post_types'] ); 
  78.  
  79. // Themes can allow Featured Content pages 
  80. if ( isset( $theme_support[0]['post_types'] ) ) { 
  81. self::$post_types = array_merge( self::$post_types, (array) $theme_support[0]['post_types'] ); 
  82.  
  83. // register post_tag support for each post type 
  84. foreach ( self::$post_types as $post_type ) { 
  85. register_taxonomy_for_object_type( 'post_tag', $post_type ); 
  86.  
  87. /** 
  88. * Hide "featured" tag from the front-end. 
  89. * Has to run on wp_loaded so that the preview filters of the customizer 
  90. * have a chance to alter the value. 
  91. */ 
  92. public static function wp_loaded() { 
  93. if ( self::get_setting( 'hide-tag' ) ) { 
  94. add_filter( 'get_terms', array( __CLASS__, 'hide_featured_term' ), 10, 3 ); 
  95. add_filter( 'get_the_terms', array( __CLASS__, 'hide_the_featured_term' ), 10, 3 ); 
  96.  
  97. /** 
  98. * Get featured posts 
  99. * This method is not intended to be called directly. Theme developers should 
  100. * place a filter directly in their theme and then pass its name as a value of 
  101. * the "filter" key in the array passed as the $args parameter during the call 
  102. * to: add_theme_support( 'featured-content', $args ). 
  103. * @uses Featured_Content::get_featured_post_ids() 
  104. * @return array 
  105. */ 
  106. public static function get_featured_posts() { 
  107. $post_ids = self::get_featured_post_ids(); 
  108.  
  109. // No need to query if there is are no featured posts. 
  110. if ( empty( $post_ids ) ) { 
  111. return array(); 
  112.  
  113. $featured_posts = get_posts( array( 
  114. 'include' => $post_ids,  
  115. 'posts_per_page' => count( $post_ids ),  
  116. 'post_type' => self::$post_types,  
  117. ) ); 
  118.  
  119. return $featured_posts; 
  120.  
  121. /** 
  122. * Get featured post IDs 
  123. * This function will return the an array containing the post IDs of all 
  124. * featured posts. 
  125. * Sets the "featured_content_ids" transient. 
  126. * @return array Array of post IDs. 
  127. */ 
  128. public static function get_featured_post_ids() { 
  129. // Return array of cached results if they exist. 
  130. $featured_ids = get_transient( 'featured_content_ids' ); 
  131. if ( ! empty( $featured_ids ) ) { 
  132. return array_map( 
  133. 'absint',  
  134. /** 
  135. * Filter the list of Featured Posts IDs. 
  136. * @module theme-tools 
  137. * @since 2.7.0 
  138. * @param array $featured_ids Array of post IDs. 
  139. */ 
  140. apply_filters( 'featured_content_post_ids', (array) $featured_ids ) 
  141. ); 
  142.  
  143. $settings = self::get_setting(); 
  144.  
  145. // Return empty array if no tag name is set. 
  146. $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' ); 
  147. if ( ! $term ) { 
  148. $term = get_term_by( 'id', $settings['tag-id'], 'post_tag' ); 
  149. if ( $term ) { 
  150. $tag = $term->term_id; 
  151. } else { 
  152. /** This action is documented in modules/theme-tools/featured-content.php */ 
  153. return apply_filters( 'featured_content_post_ids', array() ); 
  154.  
  155. // Back compat for installs that have the quantity option still set. 
  156. $quantity = isset( $settings['quantity'] ) ? $settings['quantity'] : self::$max_posts; 
  157.  
  158. // Query for featured posts. 
  159. $featured = get_posts( array( 
  160. 'numberposts' => $quantity,  
  161. 'post_type' => self::$post_types,  
  162. 'tax_query' => array( 
  163. array( 
  164. 'field' => 'term_id',  
  165. 'taxonomy' => 'post_tag',  
  166. 'terms' => $tag,  
  167. ),  
  168. ),  
  169. ) ); 
  170.  
  171. // Return empty array if no featured content exists. 
  172. if ( ! $featured ) { 
  173. /** This action is documented in modules/theme-tools/featured-content.php */ 
  174. return apply_filters( 'featured_content_post_ids', array() ); 
  175.  
  176. // Ensure correct format before save/return. 
  177. $featured_ids = wp_list_pluck( (array) $featured, 'ID' ); 
  178. $featured_ids = array_map( 'absint', $featured_ids ); 
  179.  
  180. set_transient( 'featured_content_ids', $featured_ids ); 
  181.  
  182. /** This action is documented in modules/theme-tools/featured-content.php */ 
  183. return apply_filters( 'featured_content_post_ids', $featured_ids ); 
  184.  
  185. /** 
  186. * Delete Transient. 
  187. * Hooks in the "save_post" action. 
  188. * @see Featured_Content::validate_settings(). 
  189. */ 
  190. public static function delete_transient() { 
  191. delete_transient( 'featured_content_ids' ); 
  192.  
  193. /** 
  194. * Exclude featured posts from the blog query when the blog is the front-page,  
  195. * and user has not checked the "Display tag content in all listings" checkbox. 
  196. * Filter the home page posts, and remove any featured post ID's from it. 
  197. * Hooked onto the 'pre_get_posts' action, this changes the parameters of the 
  198. * query before it gets any posts. 
  199. * @uses Featured_Content::get_featured_post_ids(); 
  200. * @uses Featured_Content::get_setting(); 
  201. * @param WP_Query $query 
  202. * @return WP_Query Possibly modified WP_Query 
  203. */ 
  204. public static function pre_get_posts( $query ) { 
  205.  
  206. // Bail if not home or not main query. 
  207. if ( ! $query->is_home() || ! $query->is_main_query() ) { 
  208. return; 
  209.  
  210. // Bail if the blog page is not the front page. 
  211. if ( 'posts' !== get_option( 'show_on_front' ) ) { 
  212. return; 
  213.  
  214. $featured = self::get_featured_post_ids(); 
  215.  
  216. // Bail if no featured posts. 
  217. if ( ! $featured ) { 
  218. return; 
  219.  
  220. $settings = self::get_setting(); 
  221.  
  222. // Bail if the user wants featured posts always displayed. 
  223. if ( true == $settings['show-all'] ) { 
  224. return; 
  225.  
  226. // We need to respect post ids already in the blacklist. 
  227. $post__not_in = $query->get( 'post__not_in' ); 
  228.  
  229. if ( ! empty( $post__not_in ) ) { 
  230. $featured = array_merge( (array) $post__not_in, $featured ); 
  231. $featured = array_unique( $featured ); 
  232.  
  233. $query->set( 'post__not_in', $featured ); 
  234.  
  235. /** 
  236. * Reset tag option when the saved tag is deleted. 
  237. * It's important to mention that the transient needs to be deleted, too. 
  238. * While it may not be obvious by looking at the function alone, the transient 
  239. * is deleted by Featured_Content::validate_settings(). 
  240. * Hooks in the "delete_post_tag" action. 
  241. * @see Featured_Content::validate_settings(). 
  242. * @param int $tag_id The term_id of the tag that has been deleted. 
  243. * @return void 
  244. */ 
  245. public static function delete_post_tag( $tag_id ) { 
  246. $settings = self::get_setting(); 
  247.  
  248. if ( empty( $settings['tag-id'] ) || $tag_id != $settings['tag-id'] ) { 
  249. return; 
  250.  
  251. $settings['tag-id'] = 0; 
  252. $settings = self::validate_settings( $settings ); 
  253. update_option( 'featured-content', $settings ); 
  254.  
  255. /** 
  256. * Hide featured tag from displaying when global terms are queried from 
  257. * the front-end. 
  258. * Hooks into the "get_terms" filter. 
  259. * @uses Featured_Content::get_setting() 
  260. * @param array $terms A list of term objects. This is the return value of get_terms(). 
  261. * @param array $taxonomies An array of taxonomy slugs. 
  262. * @return array $terms 
  263. */ 
  264. public static function hide_featured_term( $terms, $taxonomies, $args ) { 
  265.  
  266. // This filter is only appropriate on the front-end. 
  267. if ( is_admin() ) { 
  268. return $terms; 
  269.  
  270. // We only want to hide the featured tag. 
  271. if ( ! in_array( 'post_tag', $taxonomies ) ) { 
  272. return $terms; 
  273.  
  274. // Bail if no terms were returned. 
  275. if ( empty( $terms ) ) { 
  276. return $terms; 
  277.  
  278. // Bail if term objects are unavailable. 
  279. if ( 'all' != $args['fields'] ) { 
  280. return $terms; 
  281.  
  282. $settings = self::get_setting(); 
  283. $tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' ); 
  284.  
  285. if ( false !== $tag ) { 
  286. foreach ( $terms as $order => $term ) { 
  287. if ( is_object( $term ) && ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) ) { 
  288. unset( $terms[ $order ] ); 
  289.  
  290. return $terms; 
  291.  
  292. /** 
  293. * Hide featured tag from displaying when terms associated with a post object 
  294. * are queried from the front-end. 
  295. * Hooks into the "get_the_terms" filter. 
  296. * @uses Featured_Content::get_setting() 
  297. * @param array $terms A list of term objects. This is the return value of get_the_terms(). 
  298. * @param int $id The ID field for the post object that terms are associated with. 
  299. * @param array $taxonomy An array of taxonomy slugs. 
  300. * @return array $terms 
  301. */ 
  302. public static function hide_the_featured_term( $terms, $id, $taxonomy ) { 
  303.  
  304. // This filter is only appropriate on the front-end. 
  305. if ( is_admin() ) { 
  306. return $terms; 
  307.  
  308. // Make sure we are in the correct taxonomy. 
  309. if ( 'post_tag' != $taxonomy ) { 
  310. return $terms; 
  311.  
  312. // No terms? Return early! 
  313. if ( empty( $terms ) ) { 
  314. return $terms; 
  315.  
  316. $settings = self::get_setting(); 
  317. $tag = get_term_by( 'name', $settings['tag-name'], 'post_tag' ); 
  318.  
  319. if ( false !== $tag ) { 
  320. foreach ( $terms as $order => $term ) { 
  321. if ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) { 
  322. unset( $terms[ $order ] ); 
  323.  
  324. return $terms; 
  325.  
  326. /** 
  327. * Register custom setting on the Settings -> Reading screen. 
  328. * @uses Featured_Content::render_form() 
  329. * @uses Featured_Content::validate_settings() 
  330. * @return void 
  331. */ 
  332. public static function register_setting() { 
  333. add_settings_field( 'featured-content', __( 'Featured Content', 'jetpack' ), array( __class__, 'render_form' ), 'reading' ); 
  334.  
  335. // Register sanitization callback for the Customizer. 
  336. register_setting( 'featured-content', 'featured-content', array( __class__, 'validate_settings' ) ); 
  337.  
  338. /** 
  339. * Add settings to the Customizer. 
  340. * @param WP_Customize_Manager $wp_customize Theme Customizer object. 
  341. */ 
  342. public static function customize_register( $wp_customize ) { 
  343. $wp_customize->add_section( 'featured_content', array( 
  344. 'title' => __( 'Featured Content', 'jetpack' ),  
  345. 'description' => sprintf( __( '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' ), admin_url( '/edit.php?tag=featured' ), absint( self::$max_posts ) ),  
  346. 'priority' => 130,  
  347. 'theme_supports' => 'featured-content',  
  348. ) ); 
  349.  
  350. /** Add Featured Content settings. 
  351. * Sanitization callback registered in Featured_Content::validate_settings(). 
  352. * See http://themeshaper.com/2013/04/29/validation-sanitization-in-customizer/comment-page-1/#comment-12374 
  353. */ 
  354. $wp_customize->add_setting( 'featured-content[tag-name]', array( 
  355. 'type' => 'option',  
  356. 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),  
  357. ) ); 
  358. $wp_customize->add_setting( 'featured-content[hide-tag]', array( 
  359. 'default' => true,  
  360. 'type' => 'option',  
  361. 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),  
  362. ) ); 
  363. $wp_customize->add_setting( 'featured-content[show-all]', array( 
  364. 'default' => false,  
  365. 'type' => 'option',  
  366. 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),  
  367. ) ); 
  368.  
  369. // Add Featured Content controls. 
  370. $wp_customize->add_control( 'featured-content[tag-name]', array( 
  371. 'label' => __( 'Tag name', 'jetpack' ),  
  372. 'section' => 'featured_content',  
  373. 'theme_supports' => 'featured-content',  
  374. 'priority' => 20,  
  375. ) ); 
  376. $wp_customize->add_control( 'featured-content[hide-tag]', array( 
  377. 'label' => __( 'Hide tag from displaying in post meta and tag clouds.', 'jetpack' ),  
  378. 'section' => 'featured_content',  
  379. 'theme_supports' => 'featured-content',  
  380. 'type' => 'checkbox',  
  381. 'priority' => 30,  
  382. ) ); 
  383. $wp_customize->add_control( 'featured-content[show-all]', array( 
  384. 'label' => __( 'Display tag content in all listings.', 'jetpack' ),  
  385. 'section' => 'featured_content',  
  386. 'theme_supports' => 'featured-content',  
  387. 'type' => 'checkbox',  
  388. 'priority' => 40,  
  389. ) ); 
  390.  
  391. /** 
  392. * Enqueue the tag suggestion script. 
  393. */ 
  394. public static function enqueue_scripts() { 
  395. wp_enqueue_script( 'featured-content-suggest', plugins_url( 'js/suggest.js', __FILE__ ), array( 'suggest' ), '20131022', true ); 
  396.  
  397. /** 
  398. * Renders all form fields on the Settings -> Reading screen. 
  399. */ 
  400. public static function render_form() { 
  401. printf( __( 'The settings for Featured Content have <a href="%s">moved to Appearance → Customize</a>.', 'jetpack' ), admin_url( 'customize.php?#accordion-section-featured_content' ) ); 
  402.  
  403. /** 
  404. * Get settings 
  405. * Get all settings recognized by this module. This function will return all 
  406. * settings whether or not they have been stored in the database yet. This 
  407. * ensures that all keys are available at all times. 
  408. * In the event that you only require one setting, you may pass its name as the 
  409. * first parameter to the function and only that value will be returned. 
  410. * @param string $key The key of a recognized setting. 
  411. * @return mixed Array of all settings by default. A single value if passed as first parameter. 
  412. */ 
  413. public static function get_setting( $key = 'all' ) { 
  414. $saved = (array) get_option( 'featured-content' ); 
  415.  
  416. /** 
  417. * Filter Featured Content's default settings. 
  418. * @module theme-tools 
  419. * @since 2.7.0 
  420. * @param array $args { 
  421. * Array of Featured Content Settings 
  422. * @type int hide-tag Default is 1. 
  423. * @type int tag-id Default is 0. 
  424. * @type string tag-name Default is empty. 
  425. * @type int show-all Default is 0. 
  426. * } 
  427. */ 
  428. $defaults = apply_filters( 'featured_content_default_settings', array( 
  429. 'hide-tag' => 1,  
  430. 'tag-id' => 0,  
  431. 'tag-name' => '',  
  432. 'show-all' => 0,  
  433. ) ); 
  434.  
  435. $options = wp_parse_args( $saved, $defaults ); 
  436. $options = array_intersect_key( $options, $defaults ); 
  437.  
  438. if ( 'all' != $key ) { 
  439. return isset( $options[ $key ] ) ? $options[ $key ] : false; 
  440.  
  441. return $options; 
  442.  
  443. /** 
  444. * Validate settings 
  445. * Make sure that all user supplied content is in an expected format before 
  446. * saving to the database. This function will also delete the transient set in 
  447. * Featured_Content::get_featured_content(). 
  448. * @uses Featured_Content::delete_transient() 
  449. * @param array $input 
  450. * @return array $output 
  451. */ 
  452. public static function validate_settings( $input ) { 
  453. $output = array(); 
  454.  
  455. if ( empty( $input['tag-name'] ) ) { 
  456. $output['tag-id'] = 0; 
  457. } else { 
  458. $term = get_term_by( 'name', $input['tag-name'], 'post_tag' ); 
  459.  
  460. if ( $term ) { 
  461. $output['tag-id'] = $term->term_id; 
  462. } else { 
  463. $new_tag = wp_create_tag( $input['tag-name'] ); 
  464.  
  465. if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) ) { 
  466. $output['tag-id'] = $new_tag['term_id']; 
  467.  
  468. $output['tag-name'] = $input['tag-name']; 
  469.  
  470. $output['hide-tag'] = isset( $input['hide-tag'] ) && $input['hide-tag'] ? 1 : 0; 
  471.  
  472. $output['show-all'] = isset( $input['show-all'] ) && $input['show-all'] ? 1 : 0; 
  473.  
  474. self::delete_transient(); 
  475.  
  476. return $output; 
  477.  
  478. /** 
  479. * Removes the quantity setting from the options array. 
  480. * @return void 
  481. */ 
  482. public static function switch_theme() { 
  483. $option = (array) get_option( 'featured-content' ); 
  484.  
  485. if ( isset( $option['quantity'] ) ) { 
  486. unset( $option['quantity'] ); 
  487. update_option( 'featured-content', $option ); 
  488.  
  489. public static function jetpack_update_featured_content_for_split_terms( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { 
  490. $featured_content_settings = get_option( 'featured-content', array() ); 
  491.  
  492. // Check to see whether the stored tag ID is the one that's just been split. 
  493. if ( isset( $featured_content_settings['tag-id'] ) && $old_term_id == $featured_content_settings['tag-id'] && 'post_tag' == $taxonomy ) { 
  494. // We have a match, so we swap out the old tag ID for the new one and resave the option. 
  495. $featured_content_settings['tag-id'] = $new_term_id; 
  496. update_option( 'featured-content', $featured_content_settings );