Featured_Content

Featured Content.

Defined (1)

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

/inc/featured-content.php  
  1. class Featured_Content { 
  2.  
  3. /** 
  4. * The maximum number of posts a Featured Content area can contain. 
  5. * We define a default value here but themes can override 
  6. * this by defining a "max_posts" entry in the second parameter 
  7. * passed in the call to add_theme_support( 'featured-content' ). 
  8. * @see Featured_Content::init() 
  9. * @since Twenty Fourteen 1.0 
  10. * @static 
  11. * @access public 
  12. * @var int 
  13. */ 
  14. public static $max_posts = 15; 
  15.  
  16. /** 
  17. * Instantiate. 
  18. * All custom functionality will be hooked into the "init" action. 
  19. * @static 
  20. * @access public 
  21. * @since Twenty Fourteen 1.0 
  22. */ 
  23. public static function setup() { 
  24. add_action( 'init', array( __CLASS__, 'init' ), 30 ); 
  25.  
  26. /** 
  27. * Conditionally hook into WordPress. 
  28. * Theme must declare that they support this module by adding 
  29. * add_theme_support( 'featured-content' ); during after_setup_theme. 
  30. * If no theme support is found there is no need to hook into WordPress. 
  31. * We'll just return early instead. 
  32. * @static 
  33. * @access public 
  34. * @since Twenty Fourteen 1.0 
  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. // Return early if "featured_content_filter" has not been defined. 
  51. if ( ! isset( $theme_support[0]['featured_content_filter'] ) ) { 
  52. return; 
  53.  
  54. $filter = $theme_support[0]['featured_content_filter']; 
  55.  
  56. // Theme can override the number of max posts. 
  57. if ( isset( $theme_support[0]['max_posts'] ) ) { 
  58. self::$max_posts = absint( $theme_support[0]['max_posts'] ); 
  59.  
  60. add_filter( $filter, array( __CLASS__, 'get_featured_posts' ) ); 
  61. add_action( 'customize_register', array( __CLASS__, 'customize_register' ), 9 ); 
  62. add_action( 'admin_init', array( __CLASS__, 'register_setting' ) ); 
  63. add_action( 'switch_theme', array( __CLASS__, 'delete_transient' ) ); 
  64. add_action( 'save_post', array( __CLASS__, 'delete_transient' ) ); 
  65. add_action( 'delete_post_tag', array( __CLASS__, 'delete_post_tag' ) ); 
  66. add_action( 'customize_controls_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) ); 
  67. add_action( 'pre_get_posts', array( __CLASS__, 'pre_get_posts' ) ); 
  68. add_action( 'wp_loaded', array( __CLASS__, 'wp_loaded' ) ); 
  69.  
  70. /** 
  71. * Hide "featured" tag from the front end. 
  72. * Has to run on wp_loaded so that the preview filters of the Customizer 
  73. * have a chance to alter the value. 
  74. * @static 
  75. * @access public 
  76. * @since Twenty Fourteen 1.0 
  77. */ 
  78. public static function wp_loaded() { 
  79. if ( self::get_setting( 'hide-tag' ) ) { 
  80. add_filter( 'get_terms', array( __CLASS__, 'hide_featured_term' ), 10, 3 ); 
  81. add_filter( 'get_the_terms', array( __CLASS__, 'hide_the_featured_term' ), 10, 3 ); 
  82.  
  83. /** 
  84. * Get featured posts. 
  85. * @static 
  86. * @access public 
  87. * @since Twenty Fourteen 1.0 
  88. * @return array Array of featured posts. 
  89. */ 
  90. public static function get_featured_posts() { 
  91. $post_ids = self::get_featured_post_ids(); 
  92.  
  93. // No need to query if there is are no featured posts. 
  94. if ( empty( $post_ids ) ) { 
  95. return array(); 
  96.  
  97. $featured_posts = get_posts( array( 
  98. 'include' => $post_ids,  
  99. 'posts_per_page' => count( $post_ids ),  
  100. ) ); 
  101.  
  102. return $featured_posts; 
  103.  
  104. /** 
  105. * Get featured post IDs 
  106. * This function will return the an array containing the 
  107. * post IDs of all featured posts. 
  108. * Sets the "featured_content_ids" transient. 
  109. * @static 
  110. * @access public 
  111. * @since Twenty Fourteen 1.0 
  112. * @return array Array of post IDs. 
  113. */ 
  114. public static function get_featured_post_ids() { 
  115. // Get array of cached results if they exist. 
  116. $featured_ids = get_transient( 'featured_content_ids' ); 
  117.  
  118. if ( false === $featured_ids ) { 
  119. $settings = self::get_setting(); 
  120. $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' ); 
  121.  
  122. if ( $term ) { 
  123. // Query for featured posts. 
  124. $featured_ids = get_posts( array( 
  125. 'fields' => 'ids',  
  126. 'numberposts' => self::$max_posts,  
  127. 'suppress_filters' => false,  
  128. 'tax_query' => array( 
  129. array( 
  130. 'field' => 'term_id',  
  131. 'taxonomy' => 'post_tag',  
  132. 'terms' => $term->term_id,  
  133. ),  
  134. ),  
  135. ) ); 
  136.  
  137. // Get sticky posts if no Featured Content exists. 
  138. if ( ! $featured_ids ) { 
  139. $featured_ids = self::get_sticky_posts(); 
  140.  
  141. set_transient( 'featured_content_ids', $featured_ids ); 
  142.  
  143. // Ensure correct format before return. 
  144. return array_map( 'absint', $featured_ids ); 
  145.  
  146. /** 
  147. * Return an array with IDs of posts maked as sticky. 
  148. * @static 
  149. * @access public 
  150. * @since Twenty Fourteen 1.0 
  151. * @return array Array of sticky posts. 
  152. */ 
  153. public static function get_sticky_posts() { 
  154. return array_slice( get_option( 'sticky_posts', array() ), 0, self::$max_posts ); 
  155.  
  156. /** 
  157. * Delete featured content ids transient. 
  158. * Hooks in the "save_post" action. 
  159. * @see Featured_Content::validate_settings(). 
  160. * @static 
  161. * @access public 
  162. * @since Twenty Fourteen 1.0 
  163. */ 
  164. public static function delete_transient() { 
  165. delete_transient( 'featured_content_ids' ); 
  166.  
  167. /** 
  168. * Exclude featured posts from the home page blog query. 
  169. * Filter the home page posts, and remove any featured post ID's from it. 
  170. * Hooked onto the 'pre_get_posts' action, this changes the parameters of 
  171. * the query before it gets any posts. 
  172. * @static 
  173. * @access public 
  174. * @since Twenty Fourteen 1.0 
  175. * @param WP_Query $query WP_Query object. 
  176. * @return WP_Query Possibly-modified WP_Query. 
  177. */ 
  178. public static function pre_get_posts( $query ) { 
  179.  
  180. // Bail if not home or not main query. 
  181. if ( ! $query->is_home() || ! $query->is_main_query() ) { 
  182. return; 
  183.  
  184. // Bail if the blog page is not the front page. 
  185. if ( 'posts' !== get_option( 'show_on_front' ) ) { 
  186. return; 
  187.  
  188. $featured = self::get_featured_post_ids(); 
  189.  
  190. // Bail if no featured posts. 
  191. if ( ! $featured ) { 
  192. return; 
  193.  
  194. // We need to respect post ids already in the blacklist. 
  195. $post__not_in = $query->get( 'post__not_in' ); 
  196.  
  197. if ( ! empty( $post__not_in ) ) { 
  198. $featured = array_merge( (array) $post__not_in, $featured ); 
  199. $featured = array_unique( $featured ); 
  200.  
  201. $query->set( 'post__not_in', $featured ); 
  202.  
  203. /** 
  204. * Reset tag option when the saved tag is deleted. 
  205. * It's important to mention that the transient needs to be deleted,  
  206. * too. While it may not be obvious by looking at the function alone,  
  207. * the transient is deleted by Featured_Content::validate_settings(). 
  208. * Hooks in the "delete_post_tag" action. 
  209. * @see Featured_Content::validate_settings(). 
  210. * @static 
  211. * @access public 
  212. * @since Twenty Fourteen 1.0 
  213. * @param int $tag_id The term_id of the tag that has been deleted. 
  214. */ 
  215. public static function delete_post_tag( $tag_id ) { 
  216. $settings = self::get_setting(); 
  217.  
  218. if ( empty( $settings['tag-id'] ) || $tag_id != $settings['tag-id'] ) { 
  219. return; 
  220.  
  221. $settings['tag-id'] = 0; 
  222. $settings = self::validate_settings( $settings ); 
  223. update_option( 'featured-content', $settings ); 
  224.  
  225. /** 
  226. * Hide featured tag from displaying when global terms are queried from the front end. 
  227. * Hooks into the "get_terms" filter. 
  228. * @static 
  229. * @access public 
  230. * @since Twenty Fourteen 1.0 
  231. * @param array $terms List of term objects. This is the return value of get_terms(). 
  232. * @param array $taxonomies An array of taxonomy slugs. 
  233. * @return array A filtered array of terms. 
  234. * @uses Featured_Content::get_setting() 
  235. */ 
  236. public static function hide_featured_term( $terms, $taxonomies, $args ) { 
  237.  
  238. // This filter is only appropriate on the front end. 
  239. if ( is_admin() ) { 
  240. return $terms; 
  241.  
  242. // We only want to hide the featured tag. 
  243. if ( ! in_array( 'post_tag', $taxonomies ) ) { 
  244. return $terms; 
  245.  
  246. // Bail if no terms were returned. 
  247. if ( empty( $terms ) ) { 
  248. return $terms; 
  249.  
  250. // Bail if term objects are unavailable. 
  251. if ( 'all' != $args['fields'] ) { 
  252. return $terms; 
  253.  
  254. $settings = self::get_setting(); 
  255. foreach ( $terms as $order => $term ) { 
  256. if ( ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) && 'post_tag' === $term->taxonomy ) { 
  257. unset( $terms[ $order ] ); 
  258.  
  259. return $terms; 
  260.  
  261. /** 
  262. * Hide featured tag from display when terms associated with a post object 
  263. * are queried from the front end. 
  264. * Hooks into the "get_the_terms" filter. 
  265. * @static 
  266. * @access public 
  267. * @since Twenty Fourteen 1.0 
  268. * @param array $terms A list of term objects. This is the return value of get_the_terms(). 
  269. * @param int $id The ID field for the post object that terms are associated with. 
  270. * @param array $taxonomy An array of taxonomy slugs. 
  271. * @return array Filtered array of terms. 
  272. * @uses Featured_Content::get_setting() 
  273. */ 
  274. public static function hide_the_featured_term( $terms, $id, $taxonomy ) { 
  275.  
  276. // This filter is only appropriate on the front end. 
  277. if ( is_admin() ) { 
  278. return $terms; 
  279.  
  280. // Make sure we are in the correct taxonomy. 
  281. if ( 'post_tag' != $taxonomy ) { 
  282. return $terms; 
  283.  
  284. // No terms? Return early! 
  285. if ( empty( $terms ) ) { 
  286. return $terms; 
  287.  
  288. $settings = self::get_setting(); 
  289. foreach ( $terms as $order => $term ) { 
  290. if ( ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) && 'post_tag' === $term->taxonomy ) { 
  291. unset( $terms[ $term->term_id ] ); 
  292.  
  293. return $terms; 
  294.  
  295. /** 
  296. * Register custom setting on the Settings -> Reading screen. 
  297. * @static 
  298. * @access public 
  299. * @since Twenty Fourteen 1.0 
  300. */ 
  301. public static function register_setting() { 
  302. register_setting( 'featured-content', 'featured-content', array( __CLASS__, 'validate_settings' ) ); 
  303.  
  304. /** 
  305. * Add settings to the Customizer. 
  306. * @static 
  307. * @access public 
  308. * @since Twenty Fourteen 1.0 
  309. * @param WP_Customize_Manager $wp_customize Customizer object. 
  310. */ 
  311. public static function customize_register( $wp_customize ) { 
  312. $wp_customize->add_section( 'featured_content', array( 
  313. 'title' => __( 'Featured Content', 'twentyfourteen' ),  
  314. 'description' => sprintf( __( 'Use a <a href="%1$s">tag</a> to feature your posts. If no posts match the tag, <a href="%2$s">sticky posts</a> will be displayed instead.', 'twentyfourteen' ),  
  315. esc_url( add_query_arg( 'tag', _x( 'featured', 'featured content default tag slug', 'twentyfourteen' ), admin_url( 'edit.php' ) ) ),  
  316. admin_url( 'edit.php?show_sticky=1' ) 
  317. ),  
  318. 'priority' => 130,  
  319. 'theme_supports' => 'featured-content',  
  320. ) ); 
  321.  
  322. // Add Featured Content settings. 
  323. $wp_customize->add_setting( 'featured-content[tag-name]', array( 
  324. 'default' => _x( 'featured', 'featured content default tag slug', 'twentyfourteen' ),  
  325. 'type' => 'option',  
  326. 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),  
  327. ) ); 
  328. $wp_customize->add_setting( 'featured-content[hide-tag]', array( 
  329. 'default' => true,  
  330. 'type' => 'option',  
  331. 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ),  
  332. ) ); 
  333.  
  334. // Add Featured Content controls. 
  335. $wp_customize->add_control( 'featured-content[tag-name]', array( 
  336. 'label' => __( 'Tag Name', 'twentyfourteen' ),  
  337. 'section' => 'featured_content',  
  338. 'priority' => 20,  
  339. ) ); 
  340. $wp_customize->add_control( 'featured-content[hide-tag]', array( 
  341. 'label' => __( 'Don’t display tag on front end.', 'twentyfourteen' ),  
  342. 'section' => 'featured_content',  
  343. 'type' => 'checkbox',  
  344. 'priority' => 30,  
  345. ) ); 
  346.  
  347. /** 
  348. * Enqueue the tag suggestion script. 
  349. * @static 
  350. * @access public 
  351. * @since Twenty Fourteen 1.0 
  352. */ 
  353. public static function enqueue_scripts() { 
  354. wp_enqueue_script( 'featured-content-suggest', get_template_directory_uri() . '/js/featured-content-admin.js', array( 'jquery', 'suggest' ), '20131022', true ); 
  355.  
  356. /** 
  357. * Get featured content settings. 
  358. * Get all settings recognized by this module. This function 
  359. * will return all settings whether or not they have been stored 
  360. * in the database yet. This ensures that all keys are available 
  361. * at all times. 
  362. * In the event that you only require one setting, you may pass 
  363. * its name as the first parameter to the function and only that 
  364. * value will be returned. 
  365. * @static 
  366. * @access public 
  367. * @since Twenty Fourteen 1.0 
  368. * @param string $key The key of a recognized setting. 
  369. * @return mixed Array of all settings by default. A single value if passed as first parameter. 
  370. */ 
  371. public static function get_setting( $key = 'all' ) { 
  372. $saved = (array) get_option( 'featured-content' ); 
  373.  
  374. $defaults = array( 
  375. 'hide-tag' => 1,  
  376. 'tag-id' => 0,  
  377. 'tag-name' => _x( 'featured', 'featured content default tag slug', 'twentyfourteen' ),  
  378. ); 
  379.  
  380. $options = wp_parse_args( $saved, $defaults ); 
  381. $options = array_intersect_key( $options, $defaults ); 
  382.  
  383. if ( 'all' != $key ) { 
  384. return isset( $options[ $key ] ) ? $options[ $key ] : false; 
  385.  
  386. return $options; 
  387.  
  388. /** 
  389. * Validate featured content settings. 
  390. * Make sure that all user supplied content is in an expected 
  391. * format before saving to the database. This function will also 
  392. * delete the transient set in Featured_Content::get_featured_content(). 
  393. * @static 
  394. * @access public 
  395. * @since Twenty Fourteen 1.0 
  396. * @param array $input Array of settings input. 
  397. * @return array Validated settings output. 
  398. */ 
  399. public static function validate_settings( $input ) { 
  400. $output = array(); 
  401.  
  402. if ( empty( $input['tag-name'] ) ) { 
  403. $output['tag-id'] = 0; 
  404. } else { 
  405. $term = get_term_by( 'name', $input['tag-name'], 'post_tag' ); 
  406.  
  407. if ( $term ) { 
  408. $output['tag-id'] = $term->term_id; 
  409. } else { 
  410. $new_tag = wp_create_tag( $input['tag-name'] ); 
  411.  
  412. if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) ) { 
  413. $output['tag-id'] = $new_tag['term_id']; 
  414.  
  415. $output['tag-name'] = $input['tag-name']; 
  416.  
  417. $output['hide-tag'] = isset( $input['hide-tag'] ) && $input['hide-tag'] ? 1 : 0; 
  418.  
  419. // Delete the featured post ids transient. 
  420. self::delete_transient(); 
  421.  
  422. return $output; 
  423. } // Featured_Content