PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.0-beta2
Elementor Website Builder – more than just a page builder v4.3.0-beta2
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / wp-rest / classes / post-query.php

post-query.php in Elementor Website Builder – more than just a page builder 4.3.0-beta2, at modules/wp-rest/classes/post-query.php

267 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\WpRest\Classes;
4
5 use Elementor\Core\Utils\Collection;
6 use Elementor\Modules\WpRest\Base\Query as Base;
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit; // Exit if accessed directly.
10 }
11
12 class Post_Query extends Base {
13 const ENDPOINT = 'post';
14 const SEARCH_FILTER_ACCEPTED_ARGS = 2;
15 const DEFAULT_FORBIDDEN_POST_TYPES = [ 'e-floating-buttons', 'e-landing-page', 'elementor_library', 'attachment', 'revision', 'nav_menu_item', 'custom_css', 'customize_changeset' ];
16 const SEARCH_IN_CONTENT_KEY = 'search_in_content';
17 const ALLOWED_KEYS_CONVERSION_MAP = [
18 'ID' => 'id',
19 'post_title' => 'label',
20 'post_type' => 'groupLabel',
21 ];
22
23 /**
24 * @param string $search_term The original search query.
25 * @param \WP_Query $wp_query The WP_Query instance.
26 * @return string Modified search query.
27 */
28 public function customize_post_query( string $search_term, \WP_Query $wp_query ) {
29 $term = $wp_query->get( 'search_term' ) ?? '';
30 $is_custom_search = $wp_query->get( 'custom_search' ) ?? false;
31
32 if ( $is_custom_search && ! empty( $term ) ) {
33 $escaped = esc_sql( $term );
34 $search_in_content = $wp_query->get( self::SEARCH_IN_CONTENT_KEY ) ?? false;
35 $search_term .= ' AND (';
36 $search_term .= "post_title LIKE '%{$escaped}%'";
37 if ( $search_in_content ) {
38 $search_term .= " OR post_content LIKE '%{$escaped}%'";
39 $search_term .= " OR post_excerpt LIKE '%{$escaped}%'";
40 }
41 if ( ctype_digit( $term ) ) {
42 $search_term .= ' OR ID = ' . intval( $term );
43 } else {
44 $search_term .= " OR ID LIKE '%{$escaped}%'";
45 }
46 $search_term .= ')';
47 }
48
49 return $search_term;
50 }
51
52 /**
53 * @param \WP_REST_Request $request
54 * @return \WP_REST_Response
55 */
56 protected function get( \WP_REST_Request $request ) {
57 $params = $request->get_params();
58 $term = trim( $params[ self::SEARCH_TERM_KEY ] ?? '' );
59
60 $keys_format_map = $this->filter_keys_conversion_map(
61 $params[ self::KEYS_CONVERSION_MAP_KEY ] ?? self::ALLOWED_KEYS_CONVERSION_MAP,
62 self::ALLOWED_KEYS_CONVERSION_MAP
63 );
64 $requested_count = $params[ self::ITEMS_COUNT_KEY ] ?? 0;
65 $validated_count = max( $requested_count, 1 );
66 $post_count = min( $validated_count, self::MAX_RESPONSE_COUNT );
67 $is_public_only = $params[ self::IS_PUBLIC_KEY ] ?? true;
68 $post_types = $this->get_post_types_from_params( $request );
69
70 $query_args = [
71 'post_type' => array_keys( $post_types ),
72 'numberposts' => $post_count,
73 'suppress_filters' => false,
74 'custom_search' => true,
75 'post_status' => $is_public_only ? 'publish' : 'any',
76 'orderby' => 'modified',
77 'order' => 'DESC',
78 ];
79
80 // for non-admins (contributors), filter by author for private posts
81 if ( ! $is_public_only && ! current_user_can( 'read_private_posts' ) ) {
82 $query_args['author'] = get_current_user_id();
83 }
84
85 if ( ! empty( $term ) ) {
86 $query_args['search_term'] = $term;
87 $query_args[ self::SEARCH_IN_CONTENT_KEY ] = $params[ self::SEARCH_IN_CONTENT_KEY ] ?? false;
88 }
89
90 if ( ! empty( $params[ self::META_QUERY_KEY ] ) && is_array( $params[ self::META_QUERY_KEY ] ) ) {
91 $query_args['meta_query'] = $params[ self::META_QUERY_KEY ];
92 }
93
94 if ( ! empty( $params[ self::TAX_QUERY_KEY ] ) && is_array( $params[ self::TAX_QUERY_KEY ] ) ) {
95 $query_args['tax_query'] = $params[ self::TAX_QUERY_KEY ];
96 }
97
98 $this->add_filter_to_customize_query();
99 $posts = new Collection( get_posts( $query_args ) );
100 $this->remove_filter_to_customize_query();
101
102 $post_type_labels = ( new Collection( $post_types ) )
103 ->map( function ( $pt ) {
104 return $pt->label;
105 } )
106 ->all();
107
108 return new \WP_REST_Response( [
109 'success' => true,
110 'data' => [
111 'value' => $posts
112 ->filter( function ( $post ) {
113 return current_user_can( 'read_post', $post->ID );
114 } )
115 ->map( function ( $post ) use ( $keys_format_map, $post_type_labels ) {
116 $post_type_label = $post->post_type;
117
118 if ( isset( $post_type_labels[ $post->post_type ] ) ) {
119 $post_type_label = $post_type_labels[ $post->post_type ];
120 }
121
122 $post_object = [
123 'ID' => $post->ID,
124 'post_title' => $post->post_title,
125 'post_type' => $post_type_label,
126 ];
127
128 return $this->translate_keys( $post_object, $keys_format_map );
129 } )
130 ->all(),
131 ],
132 ], 200 );
133 }
134
135 /**
136 * @return void
137 */
138 private function add_filter_to_customize_query() {
139 $priority = self::SEARCH_FILTER_PRIORITY;
140 $accepted_args = self::SEARCH_FILTER_ACCEPTED_ARGS;
141
142 add_filter( 'posts_search', [ $this, 'customize_post_query' ], $priority, $accepted_args );
143 }
144
145 /**
146 * @return void
147 */
148 private function remove_filter_to_customize_query() {
149 $priority = self::SEARCH_FILTER_PRIORITY;
150 $accepted_args = self::SEARCH_FILTER_ACCEPTED_ARGS;
151
152 remove_filter( 'posts_search', [ $this, 'customize_post_query' ], $priority, $accepted_args );
153 }
154
155 protected function permission_check( \WP_REST_Request $request ): bool {
156 return current_user_can( 'edit_posts' );
157 }
158
159 protected function get_endpoint_registration_args(): array {
160 return [
161 self::INCLUDED_TYPE_KEY => [
162 'description' => 'Included post types',
163 'type' => 'array',
164 'required' => false,
165 'default' => null,
166 'sanitize_callback' => fn ( ...$args ) => self::sanitize_string_array( ...$args ),
167 ],
168 self::EXCLUDED_TYPE_KEY => [
169 'description' => 'Post type to exclude',
170 'type' => 'array',
171 'required' => false,
172 'default' => self::DEFAULT_FORBIDDEN_POST_TYPES,
173 'sanitize_callback' => fn ( ...$args ) => self::sanitize_string_array( ...$args ),
174 ],
175 self::SEARCH_TERM_KEY => [
176 'description' => 'Posts to search',
177 'type' => 'string',
178 'required' => false,
179 'default' => '',
180 'sanitize_callback' => 'sanitize_text_field',
181 ],
182 self::KEYS_CONVERSION_MAP_KEY => [
183 'description' => 'Specify keys to extract and convert, i.e. ["key_1" => "new_key_1"].',
184 'type' => 'array',
185 'required' => false,
186 'default' => [
187 'ID' => 'id',
188 'post_title' => 'label',
189 'post_type' => 'groupLabel',
190 ],
191 'sanitize_callback' => fn ( ...$args ) => self::sanitize_string_array( ...$args ),
192 ],
193 self::ITEMS_COUNT_KEY => [
194 'description' => 'Posts per page',
195 'type' => 'integer',
196 'required' => false,
197 'default' => self::MAX_RESPONSE_COUNT,
198 ],
199 self::IS_PUBLIC_KEY => [
200 'description' => 'Whether to include only public post types',
201 'type' => 'boolean',
202 'required' => false,
203 'default' => true,
204 ],
205 self::META_QUERY_KEY => [
206 'description' => 'WP_Query meta_query array',
207 'type' => 'array',
208 'required' => false,
209 'default' => null,
210 'sanitize_callback' => fn ( ...$args ) => self::sanitize_string_array( ...$args ),
211 ],
212 self::TAX_QUERY_KEY => [
213 'description' => 'WP_Query tax_query array',
214 'type' => 'array',
215 'required' => false,
216 'default' => null,
217 'sanitize_callback' => fn ( ...$args ) => self::sanitize_string_array( ...$args ),
218 ],
219 self::SEARCH_IN_CONTENT_KEY => [
220 'description' => 'Whether to search within post content and excerpt in addition to title',
221 'type' => 'boolean',
222 'required' => false,
223 'default' => false,
224 ],
225 ];
226 }
227
228 protected static function get_allowed_param_keys(): array {
229 return [
230 self::EXCLUDED_TYPE_KEY,
231 self::INCLUDED_TYPE_KEY,
232 self::KEYS_CONVERSION_MAP_KEY,
233 self::META_QUERY_KEY,
234 self::TAX_QUERY_KEY,
235 self::IS_PUBLIC_KEY,
236 self::ITEMS_COUNT_KEY,
237 self::SEARCH_IN_CONTENT_KEY,
238 ];
239 }
240
241 protected static function get_keys_to_encode(): array {
242 return [
243 self::EXCLUDED_TYPE_KEY,
244 self::INCLUDED_TYPE_KEY,
245 self::KEYS_CONVERSION_MAP_KEY,
246 self::META_QUERY_KEY,
247 self::TAX_QUERY_KEY,
248 ];
249 }
250
251 private function get_post_types_from_params( \WP_REST_Request $request ) {
252 $included_types = $request->get_param( self::INCLUDED_TYPE_KEY );
253 $excluded_types = $request->get_param( self::EXCLUDED_TYPE_KEY );
254 $post_type_query_args = [
255 'public' => true,
256 ];
257
258 $post_types = get_post_types( $post_type_query_args, 'objects' );
259
260 return Collection::make( $post_types )
261 ->filter( function ( $slug, $post_type ) use ( $included_types, $excluded_types ) {
262 return ( empty( $included_types ) || in_array( $post_type, $included_types ) ) &&
263 ( empty( $excluded_types ) || ! in_array( $post_type, $excluded_types ) );
264 } )->all();
265 }
266 }
267