PluginProbe
Parse.ly / 3.14.1
Parse.ly v3.14.1
3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 3.20.2 3.20.3 All 105 releases
wp-parsely / src / RemoteAPI / content-suggestions / class-content-suggestions-base-api.php

class-content-suggestions-base-api.php in Parse.ly 3.14.1, at src/RemoteAPI/content-suggestions/class-content-suggestions-base-api.php

195 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Remote API: Base class for all Parse.ly Content Suggestion API endpoints
4 *
5 * @package Parsely
6 * @since 3.12.0
7 */
8
9 declare(strict_types=1);
10
11 namespace Parsely\RemoteAPI\ContentSuggestions;
12
13 use Parsely\Endpoints\Base_Endpoint;
14 use Parsely\Parsely;
15 use Parsely\RemoteAPI\Base_Endpoint_Remote;
16 use UnexpectedValueException;
17 use WP_Error;
18
19 /**
20 * Base API for all Parse.ly Content Suggestion API endpoints.
21 *
22 * @since 3.12.0
23 *
24 * @phpstan-import-type WP_HTTP_Request_Args from Parsely
25 */
26 abstract class Content_Suggestions_Base_API extends Base_Endpoint_Remote {
27 protected const API_BASE_URL = Parsely::PUBLIC_SUGGESTIONS_API_BASE_URL;
28
29 /**
30 * Flag to truncate the content of the request body.
31 * If set to true, the content of the request body will be truncated to a maximum length.
32 *
33 * @since 3.14.1
34 *
35 * @var bool
36 */
37 protected const TRUNCATE_CONTENT = true;
38
39 /**
40 * The maximum length of the content of the request body.
41 *
42 * @since 3.14.1
43 *
44 * @var int
45 */
46 protected const TRUNCATE_CONTENT_LENGTH = 25000;
47
48 /**
49 * Returns whether the endpoint is available for access by the current
50 * user.
51 *
52 * @since 3.14.0
53 *
54 * @return bool
55 */
56 public function is_available_to_current_user(): bool {
57 return current_user_can(
58 // phpcs:ignore WordPress.WP.Capabilities.Undetermined
59 $this->apply_capability_filters(
60 Base_Endpoint::DEFAULT_ACCESS_CAPABILITY
61 )
62 );
63 }
64
65 /**
66 * Returns the request's options for the remote API call.
67 *
68 * @since 3.12.0
69 *
70 * @return array<string, mixed> The array of options.
71 */
72 public function get_request_options(): array {
73 $options = array(
74 'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
75 'data_format' => 'body',
76 'timeout' => 60, //phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout
77 'body' => '{}',
78 );
79
80 // Add API key to request headers.
81 if ( $this->parsely->api_secret_is_set() ) {
82 $options['headers']['X-APIKEY-SECRET'] = $this->parsely->get_api_secret();
83 }
84
85 return $options;
86 }
87
88 /**
89 * Gets the URL for a particular Parse.ly API Content Suggestion endpoint.
90 *
91 * @since 3.14.0
92 *
93 * @param array<string, mixed> $query The query arguments to send to the remote API.
94 * @throws UnexpectedValueException If the endpoint constant is not defined.
95 * @throws UnexpectedValueException If the query filter constant is not defined.
96 * @return string
97 */
98 public function get_api_url( array $query = array() ): string {
99 $this->validate_required_constraints();
100
101 $query['apikey'] = $this->parsely->get_site_id();
102
103 // Remove empty entries and sort by key so the query args are in
104 // alphabetical order.
105 $query = array_filter( $query );
106 ksort( $query );
107
108 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Hook names are defined in child classes.
109 $query = apply_filters( static::QUERY_FILTER, $query );
110 return add_query_arg( $query, static::API_BASE_URL . static::ENDPOINT );
111 }
112
113 /**
114 * Sends a POST request to the Parse.ly Content Suggestion API.
115 *
116 * This method sends a POST request to the Parse.ly Content Suggestion API and returns the
117 * response. The response is either a WP_Error object in case of an error, or a decoded JSON
118 * object in case of a successful request.
119 *
120 * @since 3.13.0
121 *
122 * @param array<string|int|bool> $query An associative array containing the query
123 * parameters for the API request.
124 * @param array<string|int|bool|array<mixed>> $body An associative array containing the body
125 * parameters for the API request.
126 * @return WP_Error|object Returns a WP_Error object in case of an error, or a decoded JSON
127 * object in case of a successful request.
128 */
129 protected function post_request( array $query = array(), array $body = array() ) {
130 $full_api_url = $this->get_api_url( $query );
131
132 /**
133 * GET request options.
134 *
135 * @var WP_HTTP_Request_Args $options
136 */
137 $options = $this->get_request_options();
138 if ( count( $body ) > 0 ) {
139 $body = $this->truncate_array_content( $body );
140
141 $options['body'] = wp_json_encode( $body );
142 if ( false === $options['body'] ) {
143 return new WP_Error( 400, __( 'Unable to encode request body', 'wp-parsely' ) );
144 }
145 }
146 $response = wp_safe_remote_post( $full_api_url, $options );
147 if ( is_wp_error( $response ) ) {
148 return $response;
149 }
150
151 if ( 200 !== $response['response']['code'] ) {
152 $error = $response['response'];
153 return new WP_Error( $error['code'], $error['message'] );
154 }
155
156 $body = wp_remote_retrieve_body( $response );
157 $decoded = json_decode( $body );
158
159 if ( ! is_object( $decoded ) ) {
160 return new WP_Error( 400, __( 'Unable to decode upstream API response', 'wp-parsely' ) );
161 }
162
163 return $decoded;
164 }
165
166 /**
167 * Truncates the content of an array to a maximum length.
168 *
169 * @since 3.14.1
170 *
171 * @param string|array|mixed $content The content to truncate.
172 * @return string|array|mixed The truncated content.
173 */
174 public function truncate_array_content( $content ) {
175 if ( is_array( $content ) ) {
176 // If the content is an array, iterate over its elements.
177 foreach ( $content as $key => $value ) {
178 // Recursively process/truncate each element of the array.
179 $content[ $key ] = $this->truncate_array_content( $value );
180 }
181 return $content;
182 } elseif ( is_string( $content ) ) {
183 // If the content is a string, truncate it.
184 if ( static::TRUNCATE_CONTENT ) {
185 // Check if the string length exceeds the maximum and truncate if necessary.
186 if ( mb_strlen( $content ) > self::TRUNCATE_CONTENT_LENGTH ) {
187 return mb_substr( $content, 0, self::TRUNCATE_CONTENT_LENGTH );
188 }
189 }
190 return $content;
191 }
192 return $content;
193 }
194 }
195