Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.67% covered (success)
96.67%
29 / 30
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Post_Types
96.67% covered (success)
96.67%
29 / 30
75.00% covered (warning)
75.00%
3 / 4
7
0.00% covered (danger)
0.00%
0 / 1
 get_supported_content_types
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_supported_content_type_options
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 get_supported_content_type_objects
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
 sort_post_type_objects
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
2.01
1<?php
2/**
3 * Supported content post type discovery for Jetpack SEO.
4 *
5 * @package automattic/jetpack-seo-package
6 */
7
8namespace Automattic\Jetpack\SEO;
9
10/**
11 * Discovers the post types Jetpack SEO can list and edit via core REST.
12 */
13class Post_Types {
14
15    /**
16     * Post types that are REST-visible but not content surfaces for SEO.
17     *
18     * @var string[]
19     */
20    const EXCLUDED_POST_TYPES = array( 'attachment' );
21
22    /**
23     * Return supported post type slugs.
24     *
25     * @return string[]
26     */
27    public static function get_supported_content_types() {
28        return array_keys( self::get_supported_content_type_objects() );
29    }
30
31    /**
32     * Return supported post type options for the Content tab.
33     *
34     * @return array<int,array{slug:string,label:string}>
35     */
36    public static function get_supported_content_type_options() {
37        $options = array();
38
39        foreach ( self::get_supported_content_type_objects() as $post_type ) {
40            $options[] = array(
41                'slug'  => $post_type->name,
42                'label' => wp_strip_all_tags( $post_type->label ),
43            );
44        }
45
46        return $options;
47    }
48
49    /**
50     * Return supported post type objects keyed by slug.
51     *
52     * Supported means public, UI-visible, and REST-enabled so the SEO dashboard
53     * can both display and save the post through core-data. Attachments are
54     * excluded because their REST endpoint is media-specific, not an editable
55     * content surface for the SEO Content tab.
56     *
57     * @return \WP_Post_Type[]
58     */
59    public static function get_supported_content_type_objects() {
60        $post_types = get_post_types(
61            array(
62                'public'       => true,
63                'show_ui'      => true,
64                'show_in_rest' => true,
65            ),
66            'objects'
67        );
68
69        foreach ( self::EXCLUDED_POST_TYPES as $post_type ) {
70            unset( $post_types[ $post_type ] );
71        }
72
73        $post_types = array_filter( $post_types, 'is_post_type_viewable' );
74
75        uasort( $post_types, array( __CLASS__, 'sort_post_type_objects' ) );
76
77        return $post_types;
78    }
79
80    /**
81     * Sort core content types first, then custom types alphabetically by label.
82     *
83     * @param \WP_Post_Type $a First post type object.
84     * @param \WP_Post_Type $b Second post type object.
85     * @return int
86     */
87    private static function sort_post_type_objects( $a, $b ) {
88        $preferred = array(
89            'post' => 0,
90            'page' => 1,
91        );
92
93        $a_rank = $preferred[ $a->name ] ?? 99;
94        $b_rank = $preferred[ $b->name ] ?? 99;
95
96        if ( $a_rank !== $b_rank ) {
97            return $a_rank - $b_rank;
98        }
99
100        return strcasecmp( $a->label, $b->label );
101    }
102}