Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
WPCOM_JSON_API_List_Dropdown_Pages_Endpoint
0.00% covered (danger)
0.00%
0 / 59
0.00% covered (danger)
0.00%
0 / 6
420
0.00% covered (danger)
0.00%
0 / 1
 callback
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
12
 to_pages_by_id
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 to_pages_by_parent
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 create_dropdown_pages
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 to_dropdown_page
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
 get_page_title
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3if ( ! defined( 'ABSPATH' ) ) {
4    exit( 0 );
5}
6
7/**
8 * List dropdown pages endpoint.
9 */
10new WPCOM_JSON_API_List_Dropdown_Pages_Endpoint(
11    array(
12
13        'description'                          => 'Get a list of pages to be displayed as options in a select-a-page-dropdown.',
14        'min_version'                          => '1.1',
15        'max_version'                          => '1.1',
16
17        'group'                                => 'posts',
18        'stat'                                 => 'posts:dropdown-pages',
19
20        'method'                               => 'GET',
21        'path'                                 => '/sites/%s/dropdown-pages/',
22        'path_labels'                          => array(
23            '$site' => '(int|string) Site ID or domain',
24        ),
25
26        'allow_fallback_to_jetpack_blog_token' => true,
27
28        'example_request'                      => 'https://public-api.wordpress.com/rest/v1.1/sites/en.blog.wordpress.com/dropdown-pages/',
29    )
30);
31
32/**
33 * Endpoint class responsible for listing pages to be displayed as options in a select-a-page-dropdown.
34 *
35 * /sites/%s/dropdown-pages/ -> $blog_id
36 *
37 * @phan-constructor-used-for-side-effects
38 */
39class WPCOM_JSON_API_List_Dropdown_Pages_Endpoint extends WPCOM_JSON_API_Endpoint {
40
41    /**
42     * Page object format.
43     *
44     * @var array
45     */
46    public $dropdown_page_object_format = array(
47        'ID'       => '(int) The page ID.',
48        'title'    => '(string) The page title.',
49        'children' => '(array:dropdown_page) An array of child pages.',
50    );
51
52    /**
53     * The response format.
54     *
55     * @var array
56     */
57    public $response_format = array(
58        'found'          => '(int) The number of pages found.',
59        'dropdown_pages' => '(array:dropdown_page) An array of dropdown_page objects.',
60    );
61
62    /**
63     * List of pages indexed by their page ID.
64     *
65     * @var array<int,WP_Post>
66     */
67    private $pages_by_id = array();
68
69    /**
70     * List of pages indexed by their parent page ID.
71     *
72     * @var array<int,WP_Post>
73     */
74    private $pages_by_parent = array();
75
76    /**
77     * API callback.
78     *
79     * @param string $path - the path.
80     * @param int    $blog_id - the blog ID.
81     * @return stdClass[] $pages - An array of page objects. Each page object includes ID and title properties and may include children property. This makes each page object a tree-like data structure.
82     */
83    public function callback( $path = '', $blog_id = 0 ) {
84        $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
85        if ( is_wp_error( $blog_id ) ) {
86            return $blog_id;
87        }
88
89        $pages = get_pages();
90
91        if ( empty( $pages ) ) {
92            return array(
93                'found'          => 0,
94                'dropdown_pages' => array(),
95            );
96        }
97
98        $this->pages_by_id     = self::to_pages_by_id( $pages );
99        $this->pages_by_parent = self::to_pages_by_parent( $pages );
100        $dropdown_pages        = $this->create_dropdown_pages();
101        return array(
102            'found'          => count( $dropdown_pages ),
103            'dropdown_pages' => $dropdown_pages,
104        );
105    }
106
107    /**
108     * Convert a list of pages to a list of pages by page ID.
109     *
110     * @param array<WP_Post> $pages - array of pages.
111     * @return array<int,WP_Post> $pages_by_page_id - indexed array of pages by page ID where index is page ID.
112     */
113    private static function to_pages_by_id( $pages ) {
114        $pages_by_page_id = array();
115        foreach ( $pages as $page ) {
116            if ( isset( $page->ID ) ) {
117                $pages_by_page_id[ $page->ID ] = $page;
118            }
119        }
120        return $pages_by_page_id;
121    }
122
123    /**
124     * Convert a list of pages to a list of pages by parent.
125     *
126     * @param array<WP_Post> $pages - array of pages.
127     * @return array<int,WP_Post> $pages_by_parent - indexed array of pages by parent where index is page ID.
128     */
129    private static function to_pages_by_parent( $pages ) {
130        $pages_by_parent = array();
131        foreach ( $pages as $page ) {
132            if ( empty( $page->post_parent ) ) {
133                $pages_by_parent['root'][] = $page;
134            } else {
135                $pages_by_parent[ $page->post_parent ][] = $page;
136            }
137        }
138        return $pages_by_parent;
139    }
140
141    /**
142     * Convert a list of pages to a list of dropdown pages.
143     *
144     * @return array<stdClass> $dropdown_pages - array of dropdown pages.
145     */
146    private function create_dropdown_pages() {
147        $dropdown_pages = array();
148
149        if ( ! empty( $this->pages_by_parent['root'] ) ) {
150            foreach ( $this->pages_by_parent['root'] as $root_page ) {
151                $dropdown_pages[] = $this->to_dropdown_page( $root_page );
152            }
153        }
154
155        if ( ! empty( $this->pages_by_id ) ) {
156            // In case there were some orphans
157            // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
158            foreach ( $this->pages_by_id as $_page_id => $page ) {
159                $dropdown_pages[] = $this->to_dropdown_page( $page );
160            }
161        }
162
163        return $dropdown_pages;
164    }
165
166    /**
167     * Convert a page to a dropdown page.
168     *
169     * @param WP_Post $page - the page.
170     * @return stdClass|false $dropdown_page - the dropdown page.
171     */
172    private function to_dropdown_page( $page ) {
173        if ( ! isset( $page->ID ) ) {
174            return false;
175        }
176
177        $title = $this->get_page_title( $page );
178
179        if ( ! isset( $this->pages_by_parent[ $page->ID ] ) ) {
180            unset( $this->pages_by_id[ $page->ID ] );
181            return (object) array(
182                'ID'    => $page->ID,
183                'title' => $title,
184            );
185        }
186
187        $children = array();
188        foreach ( $this->pages_by_parent[ $page->ID ] as $child_page ) {
189            $children[] = $this->to_dropdown_page( $child_page );
190        }
191
192        unset( $this->pages_by_id[ $page->ID ] );
193        unset( $this->pages_by_parent[ $page->ID ] );
194        return (object) array(
195            'ID'       => $page->ID,
196            'title'    => $title,
197            'children' => $children,
198        );
199    }
200
201    /**
202     * Get the page title.
203     *
204     * @param WP_Post $page - the page.
205     * @return string $page_title - the page title.
206     */
207    private function get_page_title( $page ) {
208        $title = $page->post_title;
209        if ( '' === $title ) {
210            /* translators: %d: ID of a post. */
211            $title = sprintf( __( '#%d (no title)', 'jetpack' ), $page->ID );
212        }
213
214        /**
215         * Filters the page title when creating an HTML drop-down list of pages.
216         *
217         * @since 3.1.0
218         *
219         * @param string  $title Page title.
220         * @param WP_Post $page  Page data object.
221         */
222        $title = apply_filters( 'list_pages', $title, $page );
223        return $title;
224    }
225}