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