PluginProbe
Polylang / 3.7.1
Polylang v3.7.1
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / include / filter-rest-routes.php

filter-rest-routes.php in Polylang 3.7.1, at include/filter-rest-routes.php

186 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * Class to manage REST routes filterable by language.
8 *
9 * @since 3.5
10 */
11 class PLL_Filter_REST_Routes {
12 /**
13 * Cached REST routes filterable by language ordered by types.
14 *
15 * @var string[]
16 * @phpstan-var array<string, string>
17 */
18 private $filtered_routes = array();
19
20 /**
21 * @var PLL_Model
22 */
23 private $model;
24
25 /**
26 * Constructor.
27 *
28 * @since 3.5
29 *
30 * @param PLL_Model $model Shared instance of the current PLL_Model.
31 */
32 public function __construct( PLL_Model $model ) {
33 $this->model = $model;
34 }
35
36 /**
37 * Adds query parameters to preload paths.
38 *
39 * @since 3.5
40 *
41 * @param (string|string[])[] $preload_paths Array of paths to preload.
42 * @param array $args Array of query strings to add paired by key/value.
43 * @return (string|string[])[]
44 */
45 public function add_query_parameters( array $preload_paths, array $args ): array {
46 foreach ( $preload_paths as $k => $path ) {
47 if ( empty( $path ) ) {
48 continue;
49 }
50
51 $query_params = array();
52 // If the method request is OPTIONS, $path is an array and the first element is the path
53 if ( is_array( $path ) ) {
54 $temp_path = $path[0];
55 } else {
56 $temp_path = $path;
57 }
58
59 $path_parts = wp_parse_url( $temp_path );
60
61 if ( ! isset( $path_parts['path'] ) || ! $this->is_filtered( $path_parts['path'] ) ) {
62 continue;
63 }
64
65 if ( ! empty( $path_parts['query'] ) ) {
66 parse_str( $path_parts['query'], $query_params );
67 }
68
69 // Add params in query params
70 foreach ( $args as $key => $value ) {
71 $query_params[ $key ] = $value;
72 }
73
74 // Sort query params to put it in the same order as the preloading middleware does
75 ksort( $query_params );
76
77 // Replace the key by the correct path with query params reordered
78 $sorted_path = add_query_arg( urlencode_deep( $query_params ), $path_parts['path'] );
79
80 if ( is_array( $path ) ) {
81 $preload_paths[ $k ][0] = $sorted_path;
82 } else {
83 $preload_paths[ $k ] = $sorted_path;
84 }
85 }
86
87 return $preload_paths;
88 }
89
90 /**
91 * Adds inline script to declare filtered REST route on client side.
92 *
93 * @since 3.5
94 *
95 * @param string $script_handle Name of the script to add the inline script to.
96 * @return void
97 */
98 public function add_inline_script( string $script_handle ) {
99 $script_var = 'let pllFilteredRoutes = ' . (string) wp_json_encode( $this->get() );
100
101 wp_add_inline_script( $script_handle, $script_var, 'before' );
102 }
103
104 /**
105 * Returns filtered REST routes by entity type (e.g. post type or taxonomy).
106 *
107 * @since 3.5
108 *
109 * @return string[] REST routes.
110 * @phpstan-return array<string, string>
111 */
112 private function get(): array {
113 if ( ! empty( $this->filtered_routes ) ) {
114 return $this->filtered_routes;
115 }
116
117 $translatable_post_types = $this->model->get_translated_post_types();
118 $translatable_taxonomies = $this->model->get_translated_taxonomies();
119
120 $post_types = get_post_types( array( 'show_in_rest' => true ), 'objects' );
121 $taxonomies = get_taxonomies( array( 'show_in_rest' => true ), 'objects' );
122
123 $filtered_entities = $this->extract_filtered_rest_entities(
124 array_merge( $post_types, $taxonomies ),
125 array_merge( $translatable_post_types, $translatable_taxonomies )
126 );
127
128 /**
129 * Filters REST routes filterable by languages.
130 *
131 * @since 3.7
132 *
133 * @param string[] $routes Array of filterable REST routes, with types as key.
134 */
135 $this->filtered_routes = apply_filters(
136 'pll_filtered_rest_routes',
137 array_merge(
138 $filtered_entities,
139 array( 'search' => 'wp/v2/search' )
140 )
141 );
142
143 return $this->filtered_routes;
144 }
145
146 /**
147 * Tells if a given route is fileterable by language.
148 *
149 * @since 3.5
150 *
151 * @param string $rest_route Route to test.
152 * @return bool Whether the route is filterable or not.
153 */
154 private function is_filtered( string $rest_route ): bool {
155 $rest_route = trim( $rest_route );
156
157 return ! preg_match( '/\d+$/', $rest_route ) && in_array( trim( $rest_route, '/' ), $this->get(), true );
158 }
159
160 /**
161 * Extracts filterable REST route from an array of entity objects
162 * from a list of translatable entities (e.g. post types or taxonomies).
163 *
164 * @since 3.5
165 *
166 * @param object[] $rest_entities Array of post type or taxonomy objects.
167 * @param string[] $translatable_entities Array of translatable entity names.
168 * @return string[] Filtered routes.
169 * @phpstan-param array<WP_Post_Type|WP_Taxonomy> $rest_entities
170 * @phpstan-return array<string, string>
171 */
172 private function extract_filtered_rest_entities( array $rest_entities, array $translatable_entities ) {
173 $filtered_entities = array();
174 foreach ( $rest_entities as $rest_entity ) {
175 if ( in_array( $rest_entity->name, $translatable_entities, true ) ) {
176 $rest_base = empty( $rest_entity->rest_base ) ? $rest_entity->name : $rest_entity->rest_base;
177 $rest_namespace = empty( $rest_entity->rest_namespace ) ? 'wp/v2' : $rest_entity->rest_namespace;
178
179 $filtered_entities[ $rest_entity->name ] = "{$rest_namespace}/{$rest_base}";
180 }
181 }
182
183 return $filtered_entities;
184 }
185 }
186