[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[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 marked 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 * @param array $args An array of get_terms() arguments. 284 * @return array A filtered array of terms. 285 * 286 * @uses Featured_Content::get_setting() 287 */ 288 public static function hide_featured_term( $terms, $taxonomies, $args ) { 289 290 // This filter is only appropriate on the front end. 291 if ( is_admin() ) { 292 return $terms; 293 } 294 295 // We only want to hide the featured tag. 296 if ( ! in_array( 'post_tag', $taxonomies, true ) ) { 297 return $terms; 298 } 299 300 // Bail if no terms were returned. 301 if ( empty( $terms ) ) { 302 return $terms; 303 } 304 305 // Bail if term objects are unavailable. 306 if ( 'all' !== $args['fields'] ) { 307 return $terms; 308 } 309 310 $settings = self::get_setting(); 311 foreach ( $terms as $order => $term ) { 312 if ( ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) && 'post_tag' === $term->taxonomy ) { 313 unset( $terms[ $order ] ); 314 } 315 } 316 317 return $terms; 318 } 319 320 /** 321 * Hide featured tag from display when terms associated with a post object 322 * are queried from the front end. 323 * 324 * Hooks into the "get_the_terms" filter. 325 * 326 * @since Twenty Fourteen 1.0 327 * 328 * @param array $terms A list of term objects. This is the return value of get_the_terms(). 329 * @param int $id The ID field for the post object that terms are associated with. 330 * @param array $taxonomy An array of taxonomy slugs. 331 * @return array Filtered array of terms. 332 * 333 * @uses Featured_Content::get_setting() 334 */ 335 public static function hide_the_featured_term( $terms, $id, $taxonomy ) { 336 337 // This filter is only appropriate on the front end. 338 if ( is_admin() ) { 339 return $terms; 340 } 341 342 // Make sure we are in the correct taxonomy. 343 if ( 'post_tag' !== $taxonomy ) { 344 return $terms; 345 } 346 347 // No terms? Return early! 348 if ( empty( $terms ) ) { 349 return $terms; 350 } 351 352 $settings = self::get_setting(); 353 foreach ( $terms as $order => $term ) { 354 if ( ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) && 'post_tag' === $term->taxonomy ) { 355 unset( $terms[ $term->term_id ] ); 356 } 357 } 358 359 return $terms; 360 } 361 362 /** 363 * Register custom setting on the Settings -> Reading screen. 364 * 365 * @since Twenty Fourteen 1.0 366 */ 367 public static function register_setting() { 368 register_setting( 'featured-content', 'featured-content', array( __CLASS__, 'validate_settings' ) ); 369 } 370 371 /** 372 * Add settings to the Customizer. 373 * 374 * @since Twenty Fourteen 1.0 375 * 376 * @param WP_Customize_Manager $wp_customize Customizer object. 377 */ 378 public static function customize_register( $wp_customize ) { 379 $wp_customize->add_section( 380 'featured_content', 381 array( 382 'title' => __( 'Featured Content', 'twentyfourteen' ), 383 'description' => sprintf( 384 /* translators: 1: Featured tag editor URL, 2: Post editor URL. */ 385 __( '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' ), 386 esc_url( add_query_arg( 'tag', _x( 'featured', 'featured content default tag slug', 'twentyfourteen' ), admin_url( 'edit.php' ) ) ), 387 admin_url( 'edit.php?show_sticky=1' ) 388 ), 389 'priority' => 130, 390 'theme_supports' => 'featured-content', 391 ) 392 ); 393 394 // Add Featured Content settings. 395 $wp_customize->add_setting( 396 'featured-content[tag-name]', 397 array( 398 'default' => _x( 'featured', 'featured content default tag slug', 'twentyfourteen' ), 399 'type' => 'option', 400 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ), 401 ) 402 ); 403 $wp_customize->add_setting( 404 'featured-content[hide-tag]', 405 array( 406 'default' => true, 407 'type' => 'option', 408 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ), 409 ) 410 ); 411 412 // Add Featured Content controls. 413 $wp_customize->add_control( 414 'featured-content[tag-name]', 415 array( 416 'label' => __( 'Tag Name', 'twentyfourteen' ), 417 'section' => 'featured_content', 418 'priority' => 20, 419 ) 420 ); 421 $wp_customize->add_control( 422 'featured-content[hide-tag]', 423 array( 424 'label' => __( 'Don’t display tag on front end.', 'twentyfourteen' ), 425 'section' => 'featured_content', 426 'type' => 'checkbox', 427 'priority' => 30, 428 ) 429 ); 430 } 431 432 /** 433 * Enqueue the tag suggestion script. 434 * 435 * @since Twenty Fourteen 1.0 436 */ 437 public static function enqueue_scripts() { 438 wp_enqueue_script( 'featured-content-suggest', get_template_directory_uri() . '/js/featured-content-admin.js', array( 'jquery', 'suggest' ), '20211130', array( 'in_footer' => true ) ); 439 } 440 441 /** 442 * Get featured content settings. 443 * 444 * Get all settings recognized by this module. This function 445 * will return all settings whether or not they have been stored 446 * in the database yet. This ensures that all keys are available 447 * at all times. 448 * 449 * In the event that you only require one setting, you may pass 450 * its name as the first parameter to the function and only that 451 * value will be returned. 452 * 453 * @since Twenty Fourteen 1.0 454 * 455 * @param string $key The key of a recognized setting. 456 * @return mixed Array of all settings by default. A single value if passed as first parameter. 457 */ 458 public static function get_setting( $key = 'all' ) { 459 $saved = (array) get_option( 'featured-content' ); 460 461 $defaults = array( 462 'hide-tag' => 1, 463 'tag-id' => 0, 464 'tag-name' => _x( 'featured', 'featured content default tag slug', 'twentyfourteen' ), 465 ); 466 467 $options = wp_parse_args( $saved, $defaults ); 468 $options = array_intersect_key( $options, $defaults ); 469 470 if ( 'all' !== $key ) { 471 return isset( $options[ $key ] ) ? $options[ $key ] : false; 472 } 473 474 return $options; 475 } 476 477 /** 478 * Validate featured content settings. 479 * 480 * Make sure that all user supplied content is in an expected 481 * format before saving to the database. This function will also 482 * delete the transient set in Featured_Content::get_featured_content(). 483 * 484 * @since Twenty Fourteen 1.0 485 * 486 * @param array $input Array of settings input. 487 * @return array Validated settings output. 488 */ 489 public static function validate_settings( $input ) { 490 $output = array(); 491 492 if ( empty( $input['tag-name'] ) ) { 493 $output['tag-id'] = 0; 494 } else { 495 $term = get_term_by( 'name', $input['tag-name'], 'post_tag' ); 496 497 if ( $term ) { 498 $output['tag-id'] = $term->term_id; 499 } else { 500 $new_tag = wp_create_tag( $input['tag-name'] ); 501 502 if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) ) { 503 $output['tag-id'] = $new_tag['term_id']; 504 } 505 } 506 507 $output['tag-name'] = $input['tag-name']; 508 } 509 510 $output['hide-tag'] = isset( $input['hide-tag'] ) && $input['hide-tag'] ? 1 : 0; 511 512 // Delete the featured post IDs transient. 513 self::delete_transient(); 514 515 return $output; 516 } 517 } // Featured_Content 518 519 Featured_Content::setup();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |