PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.7.6
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.7.6
1.7.7 1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
image-optimization / vendor / elementor / wp-one-package / src / Admin / Services / Editor.php

Editor.php in Image Optimizer – Compress Images and Convert to WebP or AVIF 1.7.6, at vendor/elementor/wp-one-package/src/Admin/Services/Editor.php

345 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ElementorOne\Admin\Services;
4
5 use ElementorOne\Admin\Helpers\Utils;
6 use ElementorOne\Common\SupportedPlugins;
7 use ElementorOne\Connect\Classes\GrantTypes;
8 use ElementorOne\Connect\Facade;
9 use ElementorOne\Logger;
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly
13 }
14
15 /**
16 * Class Editor
17 */
18 class Editor {
19
20 const PRO_APP_TYPE = 'PLUGIN';
21 const PRO_APP_PREFIX = 'elementor_pro';
22 const CORE_APP_PREFIX = 'elementor';
23
24 const CONNECT_APP_LIBRARY = 'library';
25 const CONNECT_APP_ACTIVATE = 'activate';
26
27 const GET_CLIENT_ID_ENDPOINT = 'get_client_id';
28
29 const SITE_KEY_OPTION_NAME = 'elementor_connect_site_key';
30 const LICENSE_KEY_OPTION_NAME = 'elementor_pro_license_key';
31 const LICENSE_DATA_OPTION_NAME = '_elementor_pro_license_v2_data';
32 const LICENSE_DATA_FALLBACK_OPTION_NAME = self::LICENSE_DATA_OPTION_NAME . '_fallback';
33 const API_REQUESTS_LOCK_OPTION_NAME = '_elementor_pro_api_requests_lock';
34 const COMMON_DATA_USER_OPTION_NAME = 'elementor_connect_common_data';
35
36 /**
37 * Logger instance
38 * @var Logger
39 */
40 private Logger $logger;
41
42 /**
43 * Instance
44 * @var Editor|null
45 */
46 private static ?Editor $instance = null;
47
48 /**
49 * Get instance
50 * @return Editor|null
51 */
52 public static function instance(): ?Editor {
53 if ( ! self::$instance ) {
54 self::$instance = new self();
55 }
56 return self::$instance;
57 }
58
59 /**
60 * Constructor
61 */
62 private function __construct() {
63 $this->logger = new Logger( self::class );
64
65 // Set tracker opt-in
66 add_action( 'elementor_one/elementor_one_connected', [ $this, 'set_tracker_opt_in' ] );
67 add_action( 'elementor_one/elementor_one_disconnected', [ $this, 'set_tracker_opt_in' ] );
68
69 // Filter additional connect info
70 add_filter( 'elementor/connect/additional-connect-info', [ $this, 'filter_additional_connect_info' ], 10, 2 );
71 }
72
73 /**
74 * Get editor data URL
75 * @param string $client_id
76 * @return string
77 */
78 public function get_editor_data_url( string $client_id ): string {
79 return Client::get_client_base_url() . "/connect/api/v1/sites/{$client_id}/editor-data";
80 }
81
82 /**
83 * Get app download URL
84 * @param string $app_type
85 * @param string $app_version
86 * @return string
87 */
88 private function get_app_download_url( string $app_type, string $app_version = 'latest' ): string {
89 return Client::get_client_base_url() . "/api/v2/artifacts/{$app_type}/{$app_version}/download-link";
90 }
91
92 /**
93 * Get active license key
94 * @return string|null
95 */
96 public static function get_active_license_key(): ?string {
97 $active_license_key = get_option( self::LICENSE_KEY_OPTION_NAME, null );
98 return ! empty( $active_license_key ) ? $active_license_key : null;
99 }
100
101 /**
102 * Validate connect type
103 * @param string $connect_type
104 * @return void
105 */
106 public static function validate_connect_type( string $connect_type ): void {
107 if ( ! in_array( $connect_type, [ self::CONNECT_APP_LIBRARY, self::CONNECT_APP_ACTIVATE ], true ) ) {
108 throw new \InvalidArgumentException( 'Invalid connect type' );
109 }
110 }
111
112 /**
113 * Update editor data
114 * @param string $connect_type
115 * @param bool $deactivate_license
116 * @return void
117 */
118 public function update_editor_data( string $connect_type, bool $deactivate_license = false ): void {
119 self::validate_connect_type( $connect_type );
120
121 $client_id = Utils::get_one_connect()->data()->get_client_id();
122 if ( ! $client_id ) {
123 throw new \RuntimeException( 'Client ID is not set' );
124 }
125
126 $owner_id = Utils::get_one_connect()->data()->get_owner_user_id();
127 if ( ! $owner_id ) {
128 throw new \RuntimeException( 'Owner user ID is not set' );
129 }
130
131 try {
132 $response = Utils::get_api_client()->request(
133 $this->get_editor_data_url( $client_id ),
134 [
135 'method' => 'POST',
136 'body' => wp_json_encode( [
137 'app' => $connect_type,
138 'local_id' => $owner_id,
139 'site_key' => $this->get_site_key(),
140 'deactivate_license_key' => $deactivate_license
141 ? self::get_active_license_key()
142 : null,
143 ] ),
144 ],
145 function ( $raw_response ) {
146 return (array) json_decode( $raw_response );
147 }
148 );
149
150 // Delete license key and data if license is being deactivated
151 if ( $deactivate_license ) {
152 delete_option( self::LICENSE_KEY_OPTION_NAME );
153 delete_option( self::LICENSE_DATA_OPTION_NAME );
154 delete_option( self::LICENSE_DATA_FALLBACK_OPTION_NAME );
155 delete_option( self::API_REQUESTS_LOCK_OPTION_NAME );
156 }
157
158 // Update common data user option
159 update_user_option( $owner_id, self::COMMON_DATA_USER_OPTION_NAME, (array) $response['connectData'] );
160
161 // Update license key if it exists
162 if ( isset( $response['licenseKey'] ) ) {
163 update_option( self::LICENSE_KEY_OPTION_NAME, $response['licenseKey'] );
164 }
165 } catch ( \Throwable $th ) {
166 $this->logger->error( $th->getMessage() );
167 }
168 }
169
170 /**
171 * Delete editor data
172 * @return void
173 */
174 public function delete_editor_data(): void {
175 $client_id = Utils::get_one_connect()->data()->get_client_id();
176 if ( ! $client_id ) {
177 throw new \RuntimeException( 'Client ID is not set' );
178 }
179
180 try {
181 Utils::get_api_client()->request(
182 $this->get_editor_data_url( $client_id ),
183 [
184 'method' => 'DELETE',
185 'headers' => [
186 'X-Elementor-Pro-Client-Id' => $this->get_site_owner_client_id(),
187 ],
188 ]
189 );
190
191 delete_option( self::LICENSE_KEY_OPTION_NAME );
192 delete_option( self::LICENSE_DATA_OPTION_NAME );
193 delete_option( self::LICENSE_DATA_FALLBACK_OPTION_NAME );
194 delete_option( self::API_REQUESTS_LOCK_OPTION_NAME );
195 } catch ( \Throwable $th ) {
196 $this->logger->error( $th->getMessage() );
197 }
198 }
199
200 /**
201 * Get site key
202 * @return string
203 */
204 private function get_site_key(): string {
205 $site_key = get_option( self::SITE_KEY_OPTION_NAME );
206 if ( ! $site_key ) {
207 $site_key = md5( uniqid( wp_generate_password() ) );
208 update_option( self::SITE_KEY_OPTION_NAME, $site_key );
209 }
210 return $site_key;
211 }
212
213 /**
214 * Filter plugins API result for Elementor Pro
215 * @param \stdClass $result
216 * @return \stdClass|\WP_Error
217 */
218 public function filter_plugins_api_result( $result ) {
219 try {
220 $response = Utils::get_api_client()->request(
221 $this->get_app_download_url( self::PRO_APP_TYPE ),
222 [
223 'method' => \WP_REST_Server::READABLE,
224 ],
225 null,
226 GrantTypes::REFRESH_TOKEN
227 );
228
229 $result = new \stdClass();
230 $result->download_link = $response['downloadLink'];
231 $result->language_packs = [];
232
233 return $result;
234 } catch ( \Throwable $th ) {
235 $this->logger->error( $th->getMessage() );
236
237 return new \WP_Error(
238 'plugin_not_found',
239 'Plugin not found.',
240 json_decode( $th->getMessage(), true )
241 );
242 }
243 }
244
245 /**
246 * Filter additional connect info
247 * @param array $additional_info
248 * @param Base_App $app
249 * @return array
250 */
251 public function filter_additional_connect_info( array $additional_info, $app ): array {
252 $is_ai_request = class_exists( '\Elementor\Modules\Ai\Connect\Ai' )
253 && $app instanceof \Elementor\Modules\Ai\Connect\Ai;
254
255 $is_activate_request = class_exists( '\ElementorPro\Core\Connect\Apps\Activate' )
256 && $app instanceof \ElementorPro\Core\Connect\Apps\Activate;
257
258 if ( $is_ai_request ) {
259 $access_token = $this->get_one_connect_access_token();
260 if ( $access_token ) {
261 $additional_info['X-Elementor-One-Auth'] = $access_token;
262 }
263 } elseif ( $is_activate_request ) {
264 $inject_authorize_url = function ( $parsed_args, $url ) use ( &$inject_authorize_url ) {
265 if ( str_ends_with( $url, self::GET_CLIENT_ID_ENDPOINT ) ) {
266 $authorize_url = Utils::get_authorize_url();
267 if ( $authorize_url && is_array( $parsed_args['body'] ) ) {
268 $parsed_args['body']['one_authorize_url'] = $authorize_url;
269 }
270
271 // Remove filter after it has been applied
272 remove_filter( 'http_request_args', $inject_authorize_url, 10 );
273 }
274
275 return $parsed_args;
276 };
277
278 add_filter( 'http_request_args', $inject_authorize_url, 10, 2 );
279 }
280
281 return $additional_info;
282 }
283
284 /**
285 * Get ONE connect access token
286 * @return string|null
287 */
288 private function get_one_connect_access_token(): ?string {
289 $facade = Utils::get_connect( SupportedPlugins::ELEMENTOR );
290
291 if ( ! $facade || ! $facade->utils()->is_connected() ) {
292 return null;
293 }
294
295 $access_token = $facade->data()->get_access_token( GrantTypes::REFRESH_TOKEN );
296
297 if ( ! Utils::is_jwt_expired( $access_token ) ) {
298 return $access_token;
299 }
300
301 try {
302 [ 'access_token' => $renewed_token ] = $facade->service()->renew_access_token( GrantTypes::REFRESH_TOKEN );
303 return $renewed_token;
304 } catch ( \Throwable $th ) {
305 $this->logger->error( $th->getMessage() );
306 return null;
307 }
308 }
309
310 /**
311 * Get owner client ID
312 * @return string|null
313 */
314 public function get_site_owner_client_id(): ?string {
315 $connect_data = $this->get_site_owner_connect_data();
316 return $connect_data['client_id'] ?? null;
317 }
318
319 /**
320 * Get site owner connect data
321 * @return array|null
322 */
323 public function get_site_owner_connect_data(): ?array {
324 $owner_id = Utils::get_one_connect()->data()->get_owner_user_id();
325 if ( ! $owner_id ) {
326 return null;
327 }
328
329 $connect_data = get_user_option( self::COMMON_DATA_USER_OPTION_NAME, $owner_id );
330 return is_array( $connect_data ) ? $connect_data : null;
331 }
332
333 /**
334 * Sync Elementor tracker opt-in with ONE connect preference
335 * @param Facade $facade
336 * @return void
337 */
338 public function set_tracker_opt_in( Facade $facade ): void {
339 if ( is_callable( '\Elementor\Tracker::set_opt_in' ) ) {
340 $allow_tracking = 'yes' === $facade->data()->get_share_usage_data();
341 \Elementor\Tracker::set_opt_in( $allow_tracking );
342 }
343 }
344 }
345