PluginProbe
WP-Stateless – Google Cloud Storage / trunk
WP-Stateless – Google Cloud Storage vtrunk
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
← All changes | lib/classes/class-bootstrap.php +1241 -632 2.2.7trunk View file →
@@ -1,16 +1,27 @@
1 1 <?php
2 +
2 3 /**
3 4 * Bootstrap
4 5 *
5 6 * @since 0.2.0
6 7 */
8 +
7 9 namespace wpCloud\StatelessMedia {
8 10
9 - if( !class_exists( 'wpCloud\StatelessMedia\Bootstrap' ) ) {
11 + use Google\Cloud\Storage\StorageClient;
12 + use Google\Auth\HttpHandler\HttpHandlerFactory;
13 + use wpCloud\StatelessMedia\Sync\FileSync;
14 + use wpCloud\StatelessMedia\Sync\ImageSync;
15 + use wpCloud\StatelessMedia\Sync\NonLibrarySync;
16 + use wpCloud\StatelessMedia\Batch\BatchTaskManager;
10 17
18 + if (!class_exists('wpCloud\StatelessMedia\Bootstrap')) {
19 +
11 20 final class Bootstrap extends \UsabilityDynamics\WP\Bootstrap_Plugin {
12 21
22 + const REQUIRED_PHP_VERSION = '5.5';
23 +
13 24 /**
14 25 * Google Storage Client
15 26 * Use $this->get_client()
16 27 *
@@ -24,9 +35,9 @@
24 35 * @static
25 36 * @property $version
26 37 * @type {Object}
27 38 */
28 - public static $version = '2.1';
39 + public static $version = '3.0';
29 40
30 41 /**
31 42 * Singleton Instance Reference.
32 43 *
@@ -36,52 +47,48 @@
36 47 * @type \wpCloud\StatelessMedia\Bootstrap object
37 48 */
38 49 protected static $instance = null;
39 50
40 -
41 51 /**
42 52 * Constructor
43 53 * Attention: MUST NOT BE CALLED DIRECTLY! USE get_instance() INSTEAD!
44 - *
54 + * @param $args
45 55 * @author peshkov@UD
46 56 */
47 - protected function __construct( $args ) {
48 - parent::__construct( $args );
49 -
57 + protected function __construct($args) {
58 + /**
59 + * Need to be loaded before plugin initialization.
60 + */
61 + if ( !(defined('WP_STATELESS_COMPATIBILITY_GAE') && !WP_STATELESS_COMPATIBILITY_GAE) ) {
62 + AppEngine::instance();
63 + }
64 +
65 + parent::__construct($args);
66 +
67 + self::$version = $args['version'] ?? self::$version;
68 +
69 + /**
70 + * Add custom args to api ping request
71 + */
72 + add_filter('ud-api-client-ping-args', function ($args, $_, $__) {
73 + $args['multisite'] = is_multisite();
74 + $args['stateless_media'] = Utility::get_stateless_media_data_count();
75 + return $args;
76 + }, 10, 3);
77 +
50 78 //** Define our Admin Notices handler object */
51 - $this->errors = new Errors( array_merge( $args, array(
79 + $this->errors = new Errors(array_merge($args, array(
52 80 'type' => $this->type
53 - ) ) );
81 + )));
54 82
55 83 // Initialize compatibility modules.
56 - add_action( 'plugins_loaded', function(){
84 + add_action('plugins_loaded', function () {
85 + Addons::instance();
57 86 new Module();
58 - });
59 - }
87 + DynamicImageSupport::instance();
88 + }, 20);
60 89
61 - /**
62 - * Instantiate class.
63 - */
64 - public function init() {
65 -
66 90 /**
67 - * Copied from wp-property
68 - * Duplicates UsabilityDynamics\WP\Bootstrap_Plugin::load_textdomain();
69 - *
70 - * There is a bug with localization in lib-wp-bootstrap 1.1.3 and lower.
71 - * So we load textdomain here again, in case old version lib-wp-bootstrap is being loaded
72 - * by another plugin.
73 - *
74 - * @since 1.9.1
75 - */
76 - load_plugin_textdomain($this->domain, false, dirname(plugin_basename($this->boot_file)) . '/static/languages/');
77 -
78 - // Parse feature falgs, set constants.
79 - $this->parse_feature_flags();
80 -
81 - new SyncNonMedia();
82 -
83 - /**
84 91 * Define settings and UI.
85 92 *
86 93 * Example:
87 94 *
@@ -90,37 +97,67 @@
90 97 *
91 98 * Manually Update/Add option
92 99 * $this->set( 'sm.client_id', 'zxcvv12adffse' );
93 100 */
94 - $this->settings = new Settings();
101 + $this->settings = new Settings($this);
102 + Status::instance();
103 + }
95 104
96 - // Invoke REST API
97 - add_action( 'rest_api_init', array( $this, 'api_init' ) );
105 + /**
106 + * Prevent loading of textdomain
107 + */
108 + public function load_textdomain() {
109 + }
98 110
111 + /**
112 + * Instantiate class.
113 + */
114 + public function init() {
115 + // Parse feature flags, set constants.
116 + $this->parse_feature_flags();
117 + $sm_mode = $this->get('sm.mode');
118 +
99 119 /**
100 - * Register SM metaboxes
120 + * Send admin email
101 121 */
102 - add_action( 'admin_init', array( $this, 'register_metaboxes' ) );
122 + add_action('wp_stateless_send_admin_email', array($this, 'send_admin_email'), 10, 3);
103 123
124 + // Should be created unconditionally and as early as possible to handle batch migration requests
125 + Migrator::instance();
126 + BatchTaskManager::instance();
127 +
128 + new SyncNonMedia();
129 +
130 + ImageSync::instance();
131 + FileSync::instance();
132 + NonLibrarySync::instance();
133 +
134 + // Invoke REST API
135 + add_action('rest_api_init', array($this, 'api_init'));
136 +
137 + // Register meta boxes and fields for media edit page
138 + add_filter('rwmb_meta_boxes', array($this, 'attachment_meta_box_callback'));
139 +
140 + // Register meta boxes and fields for media modal page
141 + add_filter('attachment_fields_to_edit', array($this, 'attachment_modal_meta_box_callback'), 11, 2);
142 +
143 + // Get the REST API root
144 + add_filter('wp_stateless_rest_api_root', array($this, 'get_rest_api_root'));
145 +
104 146 /**
105 147 * Init hook
106 148 */
107 - add_action( 'admin_init', array( $this, 'admin_init' ) );
149 + add_action('admin_init', array($this, 'admin_init'));
108 150
109 151 /**
110 - * Add custom actions to media rows
111 - */
112 - add_filter( 'media_row_actions', array( $this, 'add_custom_row_actions' ), 10, 3 );
113 -
114 - /**
115 152 * Handle switch blog properly.
116 153 */
117 - add_action( 'switch_blog', array( $this, 'on_switch_blog' ), 10, 2 );
154 + add_action('switch_blog', array($this, 'on_switch_blog'), 10, 2);
118 155
119 156 /**
120 157 * Filter for getting stateless settings
121 158 */
122 - add_filter( 'stateless::get_settings', array( $this, 'get_settings' ), 10);
159 + add_filter('stateless::get_settings', array($this, 'get_settings'), 10);
123 160
124 161 /**
125 162 * Init AJAX jobs
126 163 */
@@ -128,97 +165,211 @@
128 165
129 166 /**
130 167 * Load WP-CLI Commands
131 168 */
132 - if( defined( 'WP_CLI' ) && WP_CLI ) {
169 + if (defined('WP_CLI') && WP_CLI) {
133 170 include_once($this->path('lib/cli/class-sm-cli-command.php', 'dir'));
134 171 }
135 172
136 - $this->is_network_detected();
173 + /**
174 + * Add scripts
175 + */
176 + add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
137 177
138 178 /**
139 - * Add scripts
179 + * Delete table when blog is deleted.
140 180 */
141 - add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
181 + add_action('wp_delete_site', array($this, 'wp_delete_site'));
142 182
143 183 /**
144 - * Hashify file name if option is enabled
184 + * To prevent fatal errors for users who use PHP 5.5 or less.
145 185 */
146 - if ( $this->get( 'sm.hashify_file_name' ) == 'true' ) {
147 - add_filter('sanitize_file_name', array( 'wpCloud\StatelessMedia\Utility', 'randomize_filename' ), 10);
186 + if (version_compare(PHP_VERSION, self::REQUIRED_PHP_VERSION, '<')) {
187 + $this->errors->add(sprintf(__('The plugin requires PHP %s or higher. You current PHP version %s is too old.', ud_get_stateless_media()->domain), '<b>' . self::REQUIRED_PHP_VERSION . '</b>', '<b>' . PHP_VERSION . '</b>'));
148 188 }
149 189
150 190 /**
151 - * Delete table when blog is deleted.
191 + * Add the currently processing nag
152 192 */
153 - add_action( 'wp_delete_site', array($this, 'wp_delete_site'));
193 + foreach (Utility::get_available_sync_classes() as $process) {
194 + if ($process->is_running()) {
195 + $this->errors->add([
196 + 'title' => __('Media Library Synchronization Underway', ud_get_stateless_media()->domain),
197 + 'message' => __('WP-Stateless is synchronizing your media library in accordance with the Mode setting. You can view progress or stop the process via the WP-Stateless Sync settings area.', ud_get_stateless_media()->domain),
198 + 'button' => __('View Synchronization', ud_get_stateless_media()->domain),
199 + 'button_link' => admin_url('upload.php?page=stateless-settings&tab=stless_sync_tab'),
200 + 'key' => 'processing-in-progress'
201 + ], 'message');
202 + break;
203 + }
204 + }
154 205
155 206 /* Initialize plugin only if Mode is not 'disabled'. */
156 - if ( $this->get( 'sm.mode' ) !== 'disabled' ) {
207 + if (($sm_mode !== 'disabled' && $sm_mode !== 'stateless') || ($sm_mode === 'stateless' && (wp_doing_ajax() || wp_doing_cron()))) {
157 208
158 209 /**
159 - * Override Cache Control is option is enabled
210 + * Determine if we have issues with connection to Google Storage Bucket
211 + * if SM is not disabled.
160 212 */
161 - $cacheControl = trim($this->get( 'sm.cache_control' ));
162 - if ( !empty($cacheControl) ) {
163 - add_filter( 'sm:item:cacheControl', array( $this, 'override_cache_control' ) );
213 + $is_connected = $this->is_connected_to_gs();
214 +
215 + if (is_wp_error($is_connected)) {
216 + $this->errors->add($is_connected->get_error_message(), 'warning', false);
164 217 }
165 218
219 + if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
220 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
221 + }
222 +
166 223 /**
224 + * Carry on only if we do not have errors.
225 + */
226 + if (!$this->has_errors()) {
227 +
228 + if (in_array($sm_mode, array('cdn', 'ephemeral', 'stateless'))) {
229 + /**
230 + * init main filters
231 + */
232 + $this->_init_filters('main');
233 + }
234 +
235 + if ($sm_mode === 'ephemeral' || $sm_mode === 'stateless') {
236 + // Store attachment id in a static variable on 'intermediate_image_sizes_advanced' filter.
237 + // Utility::store_can_delete_attachment();
238 + if (function_exists('is_wp_version_compatible') && is_wp_version_compatible('5.3-RC4-46673')) {
239 + add_filter('intermediate_image_sizes_advanced', array('wpCloud\StatelessMedia\Utility', 'store_can_delete_attachment'), 10, 3);
240 + }
241 + }
242 +
243 + if ($sm_mode === 'stateless') {
244 + /**
245 + * Replacing local path to gs:// for using it on StreamWrapper
246 + */
247 + add_filter('upload_dir', array($this, 'filter_upload_dir'), 99);
248 +
249 + /**
250 + * Stateless mode working only with GD library
251 + */
252 + add_filter('wp_image_editors', array($this, 'select_wp_image_editors'));
253 +
254 + /**
255 + * Init GS client
256 + */
257 + global $gs_client;
258 + if ($gs_client = $this->init_gs_client()) {
259 + StreamWrapper::register($gs_client);
260 + }
261 + }
262 +
263 + if ($this->get('sm.delete_remote') == 'true') {
264 + /**
265 + * On physical file deletion we remove any from GS
266 + * We need priority grater than default (10) for ShortPixel plugin to work properly.
267 + */
268 + add_filter('delete_attachment', array($this, 'remove_media'), 11);
269 + }
270 +
271 + /**
272 + * init client's filters
273 + */
274 + $this->_init_filters('client');
275 + }
276 + } elseif ($sm_mode == 'stateless') {
277 + /**
167 278 * Determine if we have issues with connection to Google Storage Bucket
168 279 * if SM is not disabled.
169 280 */
170 281 $is_connected = $this->is_connected_to_gs();
171 282
172 - if ( is_wp_error( $is_connected ) ) {
173 - $this->errors->add( $is_connected->get_error_message() );
283 + if (is_wp_error($is_connected)) {
284 + $this->errors->add($is_connected->get_error_message(), 'warning', false);
174 285 }
175 286
176 - if ( $googleSDKVersionConflictError = get_transient( "wp_stateless_google_sdk_conflict" ) ) {
177 - $this->errors->add( $googleSDKVersionConflictError, 'warning' );
287 + if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
288 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
178 289 }
179 290
180 - // To prevent fatal errors for users who use PHP 5.5 or less.
181 - if( version_compare(PHP_VERSION, '5.5', '<') ) {
182 - $this->errors->add( sprintf( __( 'The plugin requires PHP %s or higher. You current PHP version %s is too old.', ud_get_stateless_media()->domain ), '<b>5.5</b>', '<b>' . PHP_VERSION . '</b>' ) );
183 - }
184 -
185 - /** Temporary fix to WP 4.4 srcset feature **/
186 - //add_filter( 'max_srcset_image_width', function(){return 1;} );
187 -
188 291 /**
189 292 * Carry on only if we do not have errors.
190 293 */
191 - if( !$this->has_errors() ) {
294 + if (!$this->has_errors()) {
295 + /**
296 + * Replacing local path to gs:// for using it on StreamWrapper
297 + */
298 + add_filter('upload_dir', array($this, 'filter_upload_dir'), 99);
192 299
193 - if( $this->get( 'sm.mode' ) === 'cdn' || $this->get( 'sm.mode' ) === 'stateless' ) {
194 - add_filter( 'wp_get_attachment_image_attributes', array( $this, 'wp_get_attachment_image_attributes' ), 20, 3 );
195 - add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 20, 2 );
196 - add_filter( 'attachment_url_to_postid', array( $this, 'attachment_url_to_postid' ), 20, 2 );
300 + /**
301 + * Stateless mode working only with GD library
302 + */
303 + add_filter('wp_image_editors', array($this, 'select_wp_image_editors'));
197 304
198 - if ( $this->get( 'sm.body_rewrite' ) == 'true' || $this->get( 'sm.body_rewrite' ) == 'enable_editor' ) {
199 - add_filter( 'the_content', array( $this, 'the_content_filter' ), 99 );
200 - }
305 + /**
306 + * Init GS client
307 + */
308 + global $gs_client;
309 + if ($gs_client = $this->init_gs_client()) {
310 + StreamWrapper::register($gs_client);
311 + }
201 312
202 - if ( $this->get( 'sm.body_rewrite' ) == 'true' || $this->get( 'sm.body_rewrite' ) == 'enable_meta' ) {
203 - add_filter( 'get_post_metadata', array( $this, 'post_metadata_filter' ), 2, 4 );
204 - }
313 + /**
314 + * init client's filters
315 + */
316 + $this->_init_filters('client');
205 317
206 - add_filter( 'wp_stateless_bucket_link', array( $this, 'wp_stateless_bucket_link' ) );
318 + /**
319 + * init main filters
320 + */
321 + $this->_init_filters('main');
322 + }
323 + }
324 + }
325 +
326 + /**
327 + * Init additional filters which uses on all modes
328 + * @param string $type
329 + */
330 + private function _init_filters($type = '') {
331 + switch ($type) {
332 + case 'main':
333 + add_filter('wp_get_attachment_image_attributes', array($this, 'wp_get_attachment_image_attributes'), 20, 3);
334 + add_filter('wp_get_attachment_url', array($this, 'wp_get_attachment_url'), 20, 2);
335 + add_filter('get_attached_file', array($this, 'get_attached_file'), 9, 2);
336 + add_filter('attachment_url_to_postid', array($this, 'attachment_url_to_postid'), 20, 2);
337 +
338 + if ($this->get('sm.body_rewrite') == 'true' || $this->get('sm.body_rewrite') == 'enable_editor') {
339 + add_filter('the_content', array($this, 'the_content_filter'), 99);
207 340 }
208 341
209 - add_filter( 'wp_stateless_file_name', array( $this, 'handle_root_dir' ) );
342 + if ($this->get('sm.body_rewrite') == 'true' || $this->get('sm.body_rewrite') == 'enable_meta') {
343 + add_filter('get_post_metadata', array($this, 'post_metadata_filter'), 2, 4);
344 + }
210 345
346 + add_filter('wp_stateless_bucket_link', array($this, 'wp_stateless_bucket_link'));
347 + break;
348 + case 'client':
211 349 /**
212 - * Rewrite Image URLS
350 + * Add custom actions to media rows
213 351 */
214 - add_filter( 'image_downsize', array( $this, 'image_downsize' ), 99, 3 );
215 - add_filter( 'wp_calculate_image_srcset', array($this, 'wp_calculate_image_srcset'), 10, 5 );
352 + add_filter('media_row_actions', array($this, 'add_custom_row_actions'), 10, 3);
216 353
217 354 /**
355 + * Hashify file name if option is enabled
356 + */
357 + if ($this->get('sm.hashify_file_name') == 'true') {
358 + add_filter('sanitize_file_name', array('wpCloud\StatelessMedia\Utility', 'randomize_filename'), 10);
359 + }
360 +
361 + /**
362 + * Override Cache Control if option is enabled
363 + */
364 + add_filter('sm:item:cacheControl', array($this->settings, 'override_cache_control'));
365 +
366 + add_filter('wp_stateless_file_name', array($this, 'handle_root_dir'), 10, 4);
367 +
368 + /**
218 369 * Extends metadata by adding GS information.
219 370 */
220 - add_filter( 'wp_get_attachment_metadata', array( $this, 'wp_get_attachment_metadata' ), 10, 2 );
371 + add_filter('wp_get_attachment_metadata', array($this, 'wp_get_attachment_metadata'), 10, 2);
221 372
222 373 /**
223 374 * Add/Edit Media
224 375 *
@@ -224,59 +375,148 @@
224 375 *
225 376 * Once added or edited we can get into Attachment ID then get all image sizes and sync them with GS
226 377 * We can't use this. That's prevent removing this filter.
227 378 */
228 - add_filter( 'wp_update_attachment_metadata', array( 'wpCloud\StatelessMedia\Utility', 'add_media' ), 999, 2 );
229 -
379 + add_filter('wp_update_attachment_metadata', array('wpCloud\StatelessMedia\Utility', 'add_media'), 999, 2);
380 +
230 381 /**
231 - * Upload the full size image first.
232 - *
382 + * Delete original in the end of generating metadata
383 + * it does not work with PDF
233 384 */
234 - if(!defined('WP_STATELESS_MEDIA_DISABLE_FULL_IMAGE_FIRST') || WP_STATELESS_MEDIA_DISABLE_FULL_IMAGE_FIRST != true){
235 - add_filter( 'intermediate_image_sizes_advanced', array( $this, 'before_intermediate_image_sizes' ), 10, 2 );
236 - }
385 + // add_filter('wp_generate_attachment_metadata', function ($metadata, $attachment_id, $state) {
386 + // if (!in_array(ud_get_stateless_media()->get('sm.mode'), array('ephemeral'))) return $metadata;
387 + // @unlink(get_attached_file($attachment_id, true));
388 + // return $metadata;
389 + // }, 99, 3);
237 390
238 391 /**
239 - * Add Media
240 - *
241 - * Once added we can get into Attachment ID then get all image sizes and sync them with GS
392 + * Rewrite Image URLS
242 393 */
243 - // add_filter( 'wp_generate_attachment_metadata', array( $this, 'add_media' ), 100, 2 );
394 + add_filter('image_downsize', array($this, 'image_downsize'), 99, 3);
395 + add_filter('wp_calculate_image_srcset', array($this, 'wp_calculate_image_srcset'), 10, 5);
244 396
245 - if ( $this->get( 'sm.delete_remote' ) == 'true' ) {
246 - /**
247 - * On physical file deletion we remove any from GS
248 - */
249 - add_filter('delete_attachment', array($this, 'remove_media'));
250 - }
397 + /**
398 + * Trigger module initialization and registration.
399 + */
400 + do_action('sm::module::init', $this->get('sm'));
251 401
252 - // Trigger module initialization and registration.
253 - do_action('sm::module::init', $this->get( 'sm' ));
254 - }
402 + break;
403 + case 'default':
404 + break;
405 + }
406 + }
255 407
408 + /**
409 + * The default $editors value:
410 + *
411 + * array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' )
412 + * @param $editors
413 + * @return array
414 + */
415 + public function select_wp_image_editors($editors) {
416 + return array('WP_Image_Editor_GD');
417 + }
418 +
419 + /**
420 + * @param callable|null $httpHandler
421 + * @return StorageClient
422 + * @throws \Exception
423 + */
424 + public function init_gs_client(?callable $httpHandler = null) {
425 + // May be Loading Google SDK....
426 + if (!class_exists('HttpHandlerFactory')) {
427 + include_once(ud_get_stateless_media()->path('lib/Google/vendor/autoload.php', 'dir'));
256 428 }
429 +
430 + $httpHandler = $httpHandler ? $httpHandler : HttpHandlerFactory::build();
431 +
432 + $json_key = json_decode($this->settings->get('sm.key_json'), true);
433 +
434 + if (!empty($json_key)) {
435 + return new StorageClient(
436 + [
437 + 'keyFile' => $json_key,
438 + 'httpHandler' => function ($request, $options) use ($httpHandler) {
439 + $xGoogApiClientHeader = $request->getHeaderLine('x-goog-api-client');
440 + $request = $request->withHeader('x-goog-api-client', $xGoogApiClientHeader);
441 +
442 + return call_user_func_array($httpHandler, [$request, $options]);
443 + },
444 + 'authHttpHandler' => HttpHandlerFactory::build(),
445 + ]
446 + );
447 + }
257 448 }
258 -
449 +
259 450 /**
451 + * Replacing root dir with GCS path
452 + * @param $uploads
453 + * @return array
454 + */
455 + public function filter_upload_dir($uploads) {
456 + global $default_dir;
457 + if ($default_dir) return $uploads;
458 + //Bucket
459 + $bucket = $this->get('sm.bucket');
460 +
461 + //Bucket folder path
462 + $root_dir = $this->get('sm.root_dir');
463 + $root_dir = apply_filters("wp_stateless_handle_root_dir", $root_dir);
464 +
465 + /**
466 + * Subdir not uses on Stateless mode
467 + */
468 + $uploads['subdir'] = '';
469 +
470 + $basedir = rtrim(sprintf('gs://%s/%s', $bucket, $root_dir), '/');
471 + $baseurl = rtrim(sprintf('https://storage.googleapis.com/%s/%s', $bucket, $root_dir), '/');
472 +
473 + $uploads = array(
474 + 'url' => rtrim($baseurl . $uploads['subdir'], '/'),
475 + 'path' => $basedir . $uploads['subdir'],
476 + 'subdir' => $uploads['subdir'],
477 + 'basedir' => $basedir,
478 + 'baseurl' => $baseurl,
479 + 'error' => false,
480 + );
481 + return $uploads;
482 + }
483 +
484 + /**
260 485 * Rebuild srcset from gs_link.
261 486 * Using calculations returned from WordPress wp_calculate_image_srcset()
262 - *
487 + *
488 + * @param $sources
489 + * @param $size_array
490 + * @param $image_src
491 + * @param $image_meta
492 + * @param $attachment_id
493 + * @return array
263 494 */
264 - public function wp_calculate_image_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id){
495 + public function wp_calculate_image_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) {
496 + $sm_mode = $this->get('sm.mode');
497 +
498 + /**
499 + * In Backup mode using local URL
500 + */
501 + if ("backup" == $sm_mode) {
502 + return $sources;
503 + }
504 +
265 505 if (empty($image_meta['gs_link'])) {
266 506 $image_meta = wp_get_attachment_metadata($attachment_id);
267 507 }
268 508
269 - if(is_array($sources) && !empty( $image_meta['gs_link'] )){
509 + if (is_array($sources) && !empty($image_meta['gs_link'])) {
270 510 $gs_name = $image_meta['gs_name'];
271 511 // getting position of root_dir in gs_name.
272 512 $root_dir_pos = strpos($gs_name, $image_meta['file']);
273 - // removing rood_dir from gs_name so we can compare to replace url with gs_link.
274 - if($root_dir_pos !== false){
513 + // removing rood_dir from gs_name so we can compare to replace url with gs_link.
514 + if ($root_dir_pos !== false) {
275 515 $gs_name = substr($gs_name, $root_dir_pos);
276 516 }
277 517
278 - if ( !isset($gs_name) || empty($gs_name) ) {
518 + if (!isset($gs_name) || empty($gs_name)) {
279 519 return [];
280 520 }
281 521
282 522 foreach ($sources as $width => &$image) {
@@ -283,9 +523,9 @@
283 523
284 524 // If srcset includes original image src, replace it
285 525 if (substr_compare($image['url'], $gs_name, -strlen($gs_name)) === 0) {
286 526 $image['url'] = $image_meta['gs_link'];
287 - // Replace all sizes
527 + // Replace all sizes
288 528 } elseif (isset($image_meta['sizes']) && is_array($image_meta['sizes'])) {
289 529 $found = false;
290 530 foreach ($image_meta['sizes'] as $key => $meta) {
291 531 if (!isset($meta['gs_name']) || empty($meta['gs_name'])) {
@@ -293,9 +533,9 @@
293 533 }
294 534
295 535 $thumb_gs_name = $meta['gs_name'];
296 536 // removing rood_dir from gs_name
297 - if($root_dir_pos !== false){
537 + if ($root_dir_pos !== false) {
298 538 $thumb_gs_name = substr($thumb_gs_name, $root_dir_pos);
299 539 }
300 540
301 541 if (substr_compare($image['url'], $thumb_gs_name, -strlen($thumb_gs_name)) === 0) {
@@ -304,22 +544,27 @@
304 544 break;
305 545 }
306 546 }
307 547
308 - // if no size found and mode is stateless and nothing to show for srcset item - unset that item
309 - if (!$found && $this->get( 'sm.mode' ) === 'stateless') {
548 + // if no size found and mode is ephemeral or stateless and nothing to show for srcset item - unset that item
549 + if (!$found && ($sm_mode === 'ephemeral' || $sm_mode === 'stateless')) {
310 550 $image = null;
311 551 }
312 552 } else {
313 553 // if mode is stateless and nothing to show for srcset item - unset that item
314 - if ( $this->get( 'sm.mode' ) === 'stateless' ) {
554 + if ($sm_mode === 'ephemeral' || $sm_mode === 'stateless') {
315 555 $image = null;
316 556 }
317 557 }
318 558 }
559 + } elseif (is_array($sources) && $sm_mode === 'stateless') {
560 + foreach ($sources as $width => &$image) {
561 + // Set default src
562 + $image['url'] = $image_src;
563 + }
319 564 }
320 565
321 - return array_filter( $sources );
566 + return is_array($sources) ? array_filter($sources) : $sources;
322 567 }
323 568
324 569 /**
325 570 * Return gs host.
@@ -329,9 +574,9 @@
329 574 * @param array $sm
330 575 * @return mixed|void
331 576 */
332 577 public function get_gs_host($sm = array()) {
333 - $sm = $sm?$sm: $this->get( 'sm');
578 + $sm = $sm ? $sm : $this->get('sm');
334 579 $image_host = 'https://storage.googleapis.com/';
335 580 $image_host .= $sm['bucket'];
336 581
337 582 $custom_domain = $sm['custom_domain'];
@@ -341,17 +586,29 @@
341 586
342 587 // checking whether the provided domain is valid.
343 588 // if the custom domain is same as the bucket name
344 589 // or the custom domain is using https.
345 - if ( !empty($sm['bucket']) && !empty($custom_domain) && $custom_domain !== 'storage.googleapis.com' && ( $is_ssl === 0 || $custom_domain == $sm['bucket'] ) ) {
590 + if (!empty($sm['bucket']) && !empty($custom_domain) && $custom_domain !== 'storage.googleapis.com' && ($is_ssl === 0 || $custom_domain == $sm['bucket'])) {
346 591 $image_host = $is_ssl === 0 ? 'https://' : 'http://'; // bucketname will be host
347 592 $image_host .= $custom_domain;
348 593 }
349 594
350 - return apply_filters( 'get_gs_host', $image_host, $image_host, $sm['bucket'], $is_ssl, $sm );
595 + return apply_filters('get_gs_host', $image_host, $image_host, $sm['bucket'], $is_ssl, $sm);
351 596 }
352 597
353 598 /**
599 + * Return gs:// path.
600 + *
601 + * @param array $sm
602 + * @return mixed|void
603 + */
604 + public function get_gs_path() {
605 + $path = 'gs://' . $this->get('sm.bucket');
606 +
607 + return apply_filters('get_gs_path', $path);
608 + }
609 +
610 + /**
354 611 * Filter for wp_stateless_bucket_link if custom domain is set.
355 612 * It's get attachment url and remove "storage.googleapis.com" from url.
356 613 * So that custom url can be used.
357 614 *
@@ -358,20 +615,19 @@
358 615 * @param $fileLink
359 616 * @return mixed|string
360 617 */
361 618 public function wp_stateless_bucket_link($fileLink) {
362 - $bucketname = $this->get( 'sm.bucket' );
363 - $custom_domain = $this->get( 'sm.custom_domain' );
619 + $bucketname = $this->get('sm.bucket');
620 + $custom_domain = $this->get('sm.custom_domain');
364 621 $is_ssl = strpos($custom_domain, 'https://') === 0;
365 622 $fileLink_is_ssl = strpos($fileLink, 'https://') === 0;
366 623 $custom_domain = str_replace(array('http://', 'https://'), '', $custom_domain);
367 624 $custom_domain = trim($custom_domain, '/');
368 -
369 - if ( $custom_domain !== 'storage.googleapis.com' && $custom_domain == $bucketname && strpos($fileLink, $bucketname) > 8 ) {
625 +
626 + if (!empty($bucketname) && $custom_domain !== 'storage.googleapis.com' && $custom_domain == $bucketname && strpos($fileLink, $bucketname) > 8) {
370 627 $fileLink = ($is_ssl ? 'https://' : 'http://') . substr($fileLink, strpos($fileLink, $bucketname));
371 - }
372 - elseif( $custom_domain !== 'storage.googleapis.com' && $custom_domain == $bucketname && $fileLink_is_ssl !== $is_ssl){
373 - if($is_ssl)
628 + } elseif ($custom_domain !== 'storage.googleapis.com' && $custom_domain == $bucketname && $fileLink_is_ssl !== $is_ssl) {
629 + if ($is_ssl)
374 630 $fileLink = str_replace(array('http://', 'https://'), 'https://', $fileLink);
375 631 else
376 632 $fileLink = str_replace(array('http://', 'https://'), 'http://', $fileLink);
377 633 }
@@ -383,19 +639,31 @@
383 639 *
384 640 * @param string $path
385 641 * @return string
386 642 */
387 - public function get_settings_page_url( $path = '' ) {
388 - $url = get_admin_url( get_current_blog_id(), ( is_network_admin() ? 'network/settings.php' : 'upload.php' ) );
643 + public function get_settings_page_url($path = '') {
644 + $url = get_admin_url(get_current_blog_id(), (is_network_admin() ? 'network/settings.php' : 'upload.php'));
389 645 return $url . $path;
390 646 }
391 647
392 648 /**
649 + * Return docs page url.
650 + *
651 + * @param string $path
652 + * @return string
653 + */
654 + public function get_docs_page_url($path = '') {
655 + $path = ltrim($path, '/');
656 +
657 + return 'https://stateless.udx.io/' . $path;
658 + }
659 +
660 + /**
393 661 * Get new blog settings once switched blog.
394 662 * @param $new_blog
395 663 * @param $prev_blog_id
396 664 */
397 - public function on_switch_blog( $new_blog, $prev_blog_id ) {
665 + public function on_switch_blog($new_blog, $prev_blog_id) {
398 666 $this->settings->refresh();
399 667 }
400 668
401 669 /**
@@ -407,37 +675,37 @@
407 675 */
408 676 public function get_settings($settings) {
409 677
410 678 $settings_list = array(
411 - 'mode',
412 - 'body_rewrite',
413 - 'body_rewrite_types',
414 - 'bucket',
415 - 'root_dir',
416 - 'key_json',
417 - 'cache_control',
418 - 'delete_remote',
419 - 'custom_domain',
420 - 'organize_media',
421 - 'hashify_file_name'
679 + 'mode',
680 + 'body_rewrite',
681 + 'body_rewrite_types',
682 + 'bucket',
683 + 'root_dir',
684 + 'key_json',
685 + 'cache_control',
686 + 'delete_remote',
687 + 'custom_domain',
688 + 'organize_media',
689 + 'hashify_file_name'
422 690 );
423 691
424 692 foreach ($settings_list as $setting) {
425 693
426 694 /** If setting is already exist, just skip it */
427 - if( isset( $settings[ $setting ] ) ) {
695 + if (isset($settings[$setting])) {
428 696 continue;
429 697 }
430 698
431 - $value = $this->get( 'sm.' . $setting );
699 + $value = $this->get('sm.' . $setting);
432 700
433 701 /** Decode json to array */
434 - if( $value && is_string( $value ) && $setting === 'key_json' ) {
435 - $value = json_decode( $value, true );
702 + if ($value && is_string($value) && $setting === 'key_json') {
703 + $value = json_decode($value, true);
436 704 $setting = 'key';
437 705 }
438 706
439 - $settings[ $setting ] = $value;
707 + $settings[$setting] = $value;
440 708 }
441 709
442 710 return $settings;
443 711 }
@@ -443,8 +711,9 @@
443 711 }
444 712
445 713 /**
446 714 * Remove all settings.
715 + * @param bool $network
447 716 */
448 717 public function reset($network = false) {
449 718 $this->settings->reset($network);
450 719 }
@@ -454,44 +723,33 @@
454 723 * @param $post
455 724 * @param $detached
456 725 * @return mixed
457 726 */
458 - public function add_custom_row_actions( $actions, $post, $detached ) {
727 + public function add_custom_row_actions($actions, $post, $detached) {
459 728
460 - if ( !current_user_can( 'upload_files' ) ) return $actions;
729 + if (!current_user_can('upload_files')) return $actions;
461 730
462 - if ( $post && 'attachment' == $post->post_type && 'image/' == substr( $post->post_mime_type, 0, 6 ) ) {
463 - $actions['sm_sync'] = '<a href="javascript:;" data-id="'.$post->ID.'" data-type="image" class="sm_inline_sync">' . __('Regenerate and Sync with GCS', ud_get_stateless_media()->domain) . '</a>';
731 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $post->ID);
732 +
733 +
734 + $sm_mode = $this->get('sm.mode');
735 + if (!empty($sm_cloud) && $sm_mode === 'stateless') return $actions;
736 +
737 + if ($post && 'attachment' == $post->post_type && 'image/' == substr($post->post_mime_type, 0, 6)) {
738 + $actions['sm_sync'] = '<a href="javascript:;" data-id="' . $post->ID . '" data-type="image" class="sm_inline_sync">' . __('Regenerate and Sync with GCS', ud_get_stateless_media()->domain) . '</a>';
464 739 }
465 740
466 - if ( $post && 'attachment' == $post->post_type && 'image/' != substr( $post->post_mime_type, 0, 6 ) ) {
467 - $actions['sm_sync'] = '<a href="javascript:;" data-id="'.$post->ID.'" data-type="other" class="sm_inline_sync">' . __('Sync with GCS', ud_get_stateless_media()->domain) . '</a>';
741 + if ($post && 'attachment' == $post->post_type && 'image/' != substr($post->post_mime_type, 0, 6)) {
742 + $actions['sm_sync'] = '<a href="javascript:;" data-id="' . $post->ID . '" data-type="other" class="sm_inline_sync">' . __('Sync with GCS', ud_get_stateless_media()->domain) . '</a>';
468 743 }
469 744
470 745 return $actions;
471 -
472 746 }
473 747
474 748 /**
475 - * Register metaboxes
476 - */
477 - public function register_metaboxes() {
478 - add_meta_box(
479 - 'sm-attachment-metabox',
480 - __( 'Google Cloud Storage', ud_get_stateless_media()->domain ),
481 - array($this, 'attachment_meta_box_callback'),
482 - 'attachment',
483 - 'side',
484 - 'low'
485 - );
486 - }
487 -
488 - /**
489 749 * Define REST API.
490 750 *
491 - * // https://usabilitydynamics-sandbox-uds-io-stateless-testing.c.rabbit.ci/wp-json/wp-stateless/v1
492 - *
493 - * @author potanin@UD
751 + * @author korotkov@UD
494 752 */
495 753 public function api_init() {
496 754
497 755 $route_namespace = 'wp-stateless/v1';
@@ -496,130 +754,305 @@
496 754
497 755 $route_namespace = 'wp-stateless/v1';
498 756 $api_namespace = 'wpCloud\StatelessMedia\API';
499 757
500 - register_rest_route( $route_namespace, '/status', array(
501 - 'methods' => 'GET',
502 - 'callback' => array( $api_namespace, 'status' ),
503 - ) );
758 + register_rest_route($route_namespace, '/status', array(
759 + 'methods' => \WP_REST_Server::READABLE,
760 + 'callback' => array($api_namespace, 'status'),
761 + 'permission_callback' => '__return_true'
762 + ));
504 763
505 - register_rest_route( $route_namespace, '/jobs', array(
506 - 'methods' => 'GET',
507 - 'callback' => array( $api_namespace, 'jobs' ),
508 - ) );
764 + register_rest_route($route_namespace, '/getSettings', array(
765 + 'methods' => \WP_REST_Server::READABLE,
766 + 'callback' => array($api_namespace, 'getSettings'),
767 + 'permission_callback' => array($api_namespace, 'authCheck')
768 + ));
509 769
510 - /**
511 - * Return stateless settings.
512 - *
513 - * Request parameter: none
514 - *
515 - * Response:
516 - * ok: Whether API is up or not
517 - * message: Describe what is done or error message on error.
518 - * settings: array of stateless settings
519 - *
520 - */
521 - register_rest_route( $route_namespace, '/getSettings', array( 'methods' => 'GET', 'callback' => array( $api_namespace, 'getSettings' ), ) );
770 + register_rest_route($route_namespace, '/updateSettings', array(
771 + 'methods' => \WP_REST_Server::CREATABLE,
772 + 'callback' => array($api_namespace, 'updateSettings'),
773 + 'permission_callback' => array($api_namespace, 'authCheck')
774 + ));
522 775
523 - /**
524 - * Essentially for scrolling through media library to build our index.
525 - *
526 - * Request parameter: none
527 - *
528 - * Response:
529 - * ok: Whether API is up or not
530 - * message: Describe what is done or error message on error.
531 - * settings: array of media files
532 - *
533 - */
534 - register_rest_route( $route_namespace, '/getMediaLibrary', array( 'methods' => 'GET', 'callback' => array( $api_namespace, 'getMediaLibrary' ), ) );
776 + register_rest_route($route_namespace, '/sync/getProcesses', array(
777 + 'methods' => \WP_REST_Server::READABLE,
778 + 'callback' => array($api_namespace, 'syncGetProcesses'),
779 + 'permission_callback' => array($api_namespace, 'authCheck')
780 + ));
535 781
536 - /**
537 - * Get detailed information of media file
538 - *
539 - * Request parameter: none
540 - *
541 - * Response:
542 - * ok: Whether API is up or not
543 - * message: Describe what is done or error message on error.
544 - * settings: media file array
545 - *
546 - */
547 - register_rest_route( $route_namespace, '/getMediaItem', array( 'methods' => 'GET', 'callback' => array( $api_namespace, 'getMediaItem' ), ) );
782 + register_rest_route($route_namespace, '/sync/getProcess/(?P<id>\S+)', array(
783 + 'methods' => \WP_REST_Server::READABLE,
784 + 'callback' => array($api_namespace, 'syncGetProcess'),
785 + 'permission_callback' => array($api_namespace, 'authCheck')
786 + ));
548 787
788 + register_rest_route($route_namespace, '/sync/run', array(
789 + 'methods' => \WP_REST_Server::CREATABLE,
790 + 'callback' => array($api_namespace, 'syncRun'),
791 + 'permission_callback' => array($api_namespace, 'authCheck')
792 + ));
793 +
794 + register_rest_route($route_namespace, '/sync/stop', array(
795 + 'methods' => \WP_REST_Server::CREATABLE,
796 + 'callback' => array($api_namespace, 'syncStop'),
797 + 'permission_callback' => array($api_namespace, 'authCheck')
798 + ));
799 +
800 + register_rest_route($route_namespace, '/batch/state', array(
801 + 'methods' => \WP_REST_Server::READABLE,
802 + 'callback' => array($api_namespace, 'batchState'),
803 + 'permission_callback' => array($api_namespace, 'authCheck')
804 + ));
805 +
806 + register_rest_route($route_namespace, '/batch/action', array(
807 + 'methods' => \WP_REST_Server::CREATABLE,
808 + 'callback' => array($api_namespace, 'batchAction'),
809 + 'permission_callback' => array($api_namespace, 'authCheck')
810 + ));
811 + }
812 +
813 + /**
814 + * Metabox for media modal page
815 + * @param $form_fields
816 + * @param $post
817 + * @return array
818 + */
819 + public function attachment_modal_meta_box_callback($form_fields, $post) {
820 + // Do not show on media edit page, only on modal
821 + // Do not show if we are not in Media Library
822 + if ( isset($_GET['post']) || wp_doing_ajax() ) {
823 + return $form_fields;
824 + }
825 +
826 + $link = get_edit_post_link($post->ID);
827 +
828 + $form_field['label'] = '';
829 + $form_field['input'] = 'html';
830 + $form_field['html'] = sprintf("<script>jQuery('.sm_edit_links').remove();jQuery('.actions').prepend('<a class=\"sm_edit_links\" href=\"%s#sm-attachment-metabox\">%s</a> | ')</script>", $link, __("View stateless meta", ud_get_stateless_media()->domain));
831 + $form_field['show_in_modal'] = true;
832 +
833 + $form_fields['sm_html'] = $form_field;
834 + return $form_fields;
549 835 }
550 836
551 837 /**
552 - * @param $post
838 + * Metabox for media edit page
839 + * @param $meta_boxes
840 + * @return array
553 841 */
554 - public function attachment_meta_box_callback( $post ) {
555 - ob_start();
842 + public function attachment_meta_box_callback($meta_boxes) {
843 + $post_id = false;
844 + if (isset($_GET['post'])) {
845 + $post_id = intval($_GET['post']);
846 + } elseif (isset($_POST['post_ID'])) {
847 + $post_id = intval($_POST['post_ID']);
848 + } elseif (isset($_GET['item'])) {
849 + $post_id = intval($_GET['item']);
850 + } elseif (isset($_POST['item'])) {
851 + $post_id = intval($_POST['item']);
852 + }
556 853
557 - $sm_cloud = get_post_meta( $post->ID, 'sm_cloud', 1 );
854 + return $this->_prepare_data_for_metabox($meta_boxes, $post_id);
855 + }
558 856
559 - if ( is_array( $sm_cloud ) && !empty( $sm_cloud[ 'fileLink' ] ) ) { ?>
857 + /**
858 + * Prepare data for metabox fields
859 + * @param $meta_boxes
860 + * @param $post_id
861 + * @return array
862 + */
863 + private function _prepare_data_for_metabox($meta_boxes, $post_id) {
864 + $post = get_post($post_id);
865 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $post_id, true);
866 + $sm_mode = $this->get('sm.mode');
560 867
561 - <?php if( !empty( $sm_cloud[ 'cacheControl' ] ) ) { ?>
562 - <div class="misc-pub-cache-control hidden">
563 - <?php _e( 'Cache Control:', ud_get_stateless_media()->domain ); ?> <strong><span><?php echo $sm_cloud[ 'cacheControl' ]; ?></span> </strong>
564 - </div>
565 - <?php } ?>
868 + if (empty($post)) {
869 + return $meta_boxes;
870 + }
566 871
567 - <div class="misc-pub-gs-file-link" style="margin-bottom: 15px;">
568 - <label>
569 - <?php _e( 'Storage Bucket URL:', ud_get_stateless_media()->domain ); ?> <a href="<?php echo $sm_cloud[ 'fileLink' ]; ?>" target="_blank" class="sm-view-link"><?php _e( '[view]' ); ?></a>
570 - <input type="text" class="widefat urlfield" readonly="readonly" value="<?php echo esc_attr($sm_cloud[ 'fileLink' ]); ?>" />
571 - </label>
572 - </div>
872 + $sizes = $this->get_image_sizes();
573 873
574 - <?php
874 + $fields = array();
575 875
576 - if ( !empty( $sm_cloud[ 'bucket' ] ) ) {
577 - ?>
578 - <div class="misc-pub-gs-bucket" style="margin-bottom: 15px;">
579 - <label>
580 - <?php _e( 'Storage Bucket:', ud_get_stateless_media()->domain ); ?>
581 - <input type="text" class="widefat urlfield" readonly="readonly" value="gs://<?php echo esc_attr($sm_cloud[ 'bucket' ]); ?>" />
582 - </label>
583 - </div>
584 - <?php
876 + if ($sm_mode !== 'stateless' || empty($sm_cloud)) {
877 + $fields[] = array(
878 + 'name' => __('Regenerate', ud_get_stateless_media()->domain),
879 + 'id' => 'storage_bucket_url',
880 + 'type' => 'custom_html',
881 + 'std' => $this->_prepare_generate_link($post, false, '', true, $sm_cloud),
882 + 'tab' => 'thumbnails',
883 + );
884 + }
885 +
886 + if (is_array($sm_cloud) && !empty($sm_cloud['fileLink'])) {
887 +
888 + $fields[] = array(
889 + 'type' => 'heading',
890 + 'name' => 'Files',
891 + 'tab' => 'thumbnails',
892 + );
893 +
894 + $fields[] = array(
895 + 'name' => __('Original', ud_get_stateless_media()->domain),
896 + 'id' => 'storage_bucket_url',
897 + 'type' => 'custom_html',
898 + 'media_modal' => true,
899 + 'std' => '<label><input type="text" class="widefat urlfield" readonly="readonly" value="' . esc_attr($sm_cloud['fileLink']) . '" />
900 + <a href="' . $sm_cloud['fileLink'] . '" target="_blank" class="sm-view-link"><i class="dashicons dashicons-external"></i></a>&nbsp;&nbsp;&nbsp;' . $this->_prepare_generate_link($post, true, '', false, $sm_cloud) . ' </label>',
901 + 'tab' => 'thumbnails',
902 + );
903 +
904 + if (!empty($sm_cloud['sizes']) && is_array($sm_cloud['sizes'])) {
905 + foreach ($sm_cloud['sizes'] as $size_label => $size) {
906 +
907 + $fields[] = array(
908 + 'name' => __(sprintf("%s x %s", ($size['width'] ?: $sizes[$size_label]['width']), ($size['height'] ?: $sizes[$size_label]['height'])), ud_get_stateless_media()->domain),
909 + 'id' => 'storage_bucket_url' . $size_label,
910 + 'type' => 'custom_html',
911 + 'media_modal' => true,
912 + 'std' => '<label><input type="text" class="widefat urlfield" readonly="readonly" value="' . esc_attr($size['fileLink']) . '" />
913 + <a href="' . $size['fileLink'] . '" target="_blank" class="sm-view-link"><i class="dashicons dashicons-external"></i></a>&nbsp;&nbsp;&nbsp;' . $this->_prepare_generate_link($post, true, $size_label, false, $sm_cloud) . ' </label>',
914 + 'tab' => 'thumbnails',
915 + );
916 + }
585 917 }
586 918
587 - if ( current_user_can( 'upload_files' ) ) {
588 - if ( $post && 'attachment' == $post->post_type && 'image/' == substr( $post->post_mime_type, 0, 6 ) ) {
589 - ?>
590 - <a href="javascript:;" data-type="image" data-id="<?php echo $post->ID; ?>"
591 - class="button-secondary sm_inline_sync"><?php _e('Regenerate and Sync with GCS', ud_get_stateless_media()->domain); ?></a>
592 - <?php
593 - }
919 + if (!empty($sm_cloud['cacheControl'])) {
920 + $fields[] = array(
921 + 'name' => __('Cache Control', ud_get_stateless_media()->domain),
922 + 'id' => 'cache_control',
923 + 'type' => 'custom_html',
924 + 'std' => '<label><input type="text" class="widefat urlfield" readonly="readonly" value="' . $sm_cloud['cacheControl'] . '" /></label>',
925 + 'tab' => 'meta',
926 + );
927 + }
594 928
595 - if ( $post && 'attachment' == $post->post_type && 'image/' != substr( $post->post_mime_type, 0, 6 ) ) {
596 - ?>
597 - <a href="javascript:;" data-type="other" data-id="<?php echo $post->ID; ?>"
598 - class="button-secondary sm_inline_sync"><?php _e('Sync with GCS', ud_get_stateless_media()->domain); ?></a>
599 - <?php
600 - }
929 + if (!empty($sm_cloud['bucket'])) {
930 + $fields[] = array(
931 + 'name' => __('Storage Bucket', ud_get_stateless_media()->domain),
932 + 'id' => 'storage_bukcet',
933 + 'type' => 'custom_html',
934 + 'std' => '<label><input type="text" class="widefat urlfield" readonly="readonly" value="gs://' . esc_attr($sm_cloud['bucket']) . '" />
935 + <a href="https://console.cloud.google.com/storage/browser/' . esc_attr($sm_cloud['bucket']) . '" target="_blank" class="sm-view-link"><i class="dashicons dashicons-external"></i></a></label>',
936 + 'tab' => 'meta',
937 + );
601 938 }
602 939 }
603 940
604 - echo apply_filters( 'sm::attachment::meta', ob_get_clean(), $post->ID );
941 + $meta_boxes[] = apply_filters('sm::attachment::meta', array(
942 + 'id' => 'sm-attachment-metabox',
943 + 'title' => __('Stateless', ud_get_stateless_media()->domain),
944 + 'post_types' => 'attachment',
945 + //'media_modal' => true,
946 + //set context `side` for left column
947 + 'context' => 'normal',
948 + 'priority' => 'low',
949 + 'tabs' => array(
950 + 'thumbnails' => array(
951 + 'label' => __('Thumbnails', ud_get_stateless_media()->domain),
952 + 'icon' => 'dashicons-format-gallery',
953 + ),
954 + 'meta' => array(
955 + 'label' => __('Meta', ud_get_stateless_media()->domain),
956 + 'icon' => 'dashicons-admin-site',
957 + ),
958 + ),
959 + // Tab style: 'default', 'box' or 'left'. Optional
960 + 'tab_style' => 'left',
961 + // Show meta box wrapper around tabs? true (default) or false. Optional
962 + 'tab_wrapper' => true,
963 + 'fields' => $fields
964 + ), $post->ID);
965 +
966 + return $meta_boxes;
605 967 }
606 968
607 969 /**
970 + * Preparing link for sync
971 + * @param $post
972 + * @param bool $use_icon
973 + * @param string $size
974 + * @param bool $button
975 + * @param array $sm_cloud
976 + * @return string
977 + */
978 + private function _prepare_generate_link($post, $use_icon = false, $size = '', $button = false, $sm_cloud = array()) {
979 + $sync = '';
980 +
981 + $sm_mode = $this->get('sm.mode');
982 +
983 + if (current_user_can('upload_files') && $sm_mode !== 'disabled' && ($sm_mode !== 'stateless' || empty($sm_cloud))) {
984 + if ($post && 'attachment' == $post->post_type && 'image/' == substr($post->post_mime_type, 0, 6)) {
985 + $sync = '<a href="javascript:;" data-type="image" data-id="' . $post->ID . '" data-size="' . $size . '" data-reload_page="' . $button . '"
986 + class="sm_inline_sync ' . ($button ? 'button button-primary button-large' : '') . '">' . ($use_icon ? "<i class='dashicons dashicons-image-rotate'></i>" : __('Regenerate and Sync with GCS', ud_get_stateless_media()->domain)) . '</a>';
987 + }
988 + if ($post && 'attachment' == $post->post_type && 'image/' != substr($post->post_mime_type, 0, 6)) {
989 + $sync = '<a href="javascript:;" data-type="other" data-id="' . $post->ID . '" data-size="' . $size . '" data-reload_page="' . $button . '"
990 + class="sm_inline_sync ' . ($button ? 'button button-primary button-large' : '') . '">' . ($use_icon ? "<i class='dashicons dashicons-image-rotate'></i>" : __('Sync with GCS', ud_get_stateless_media()->domain)) . '</a>';
991 + }
992 + } elseif ($button && $sm_mode !== 'stateless') {
993 + $sync = __('You do not have access to sync or Stateless mode is Disabled', ud_get_stateless_media()->domain);
994 + }
995 + return $sync;
996 + }
997 +
998 + /**
608 999 * @param $current_path
1000 + * @param $use_root boolean: whether to use the root dir or not.
1001 + * 0 will be passed from various compatibilities so that the root dir is not used.
1002 + * false will passed from some compatibilities to use the value as local path.
1003 + * @param $attachment_id
1004 + * @param $size
609 1005 * @return string
610 1006 */
611 - public function handle_root_dir( $current_path ) {
612 - $root_dir = $this->get( 'sm.root_dir' );
613 - $root_dir = trim( $root_dir, '/ ' ); // Remove any forward slash and empty space.
1007 + public function handle_root_dir($current_path, $use_root = true, $attachment_id = '', $size = '') {
1008 + //non media files
1009 + if ($use_root === 0) {
1010 + $non_media = ud_stateless_db()->get_non_library_file_name($current_path);
614 1011
1012 + if ($non_media) {
1013 + return $non_media;
1014 + }
1015 + }
1016 +
1017 + $root_dir = $this->get('sm.root_dir');
1018 + $root_dir_regex = '~^' . apply_filters("wp_stateless_handle_root_dir", $root_dir, true) . '/~';
1019 + /**
1020 + * Retrieve Y/M and other tags from current path
1021 + */
1022 + $path_elements = apply_filters('wp_stateless_unhandle_root_dir', $current_path);
1023 + $root_dir = apply_filters("wp_stateless_handle_root_dir", $root_dir, false, $path_elements);
1024 +
615 1025 $upload_dir = wp_upload_dir();
616 - $current_path = str_replace( wp_normalize_path( trailingslashit( $upload_dir[ 'basedir' ] ) ), '', wp_normalize_path( $current_path ) );
617 - $current_path = str_replace( wp_normalize_path( trailingslashit( $upload_dir[ 'baseurl' ] ) ), '', wp_normalize_path( $current_path ) );
1026 + $current_path = str_replace(wp_normalize_path(trailingslashit($upload_dir['basedir'])), '', wp_normalize_path($current_path));
1027 + $current_path = str_replace(wp_normalize_path(trailingslashit($upload_dir['baseurl'])), '', wp_normalize_path($current_path));
1028 + $current_path = str_replace(trailingslashit($this->get_gs_host()), '', $current_path);
618 1029
1030 + /**
1031 + * Using only filename. Other parts of path included to $root_dir.
1032 + * excluding compatibility.
1033 + */
1034 + if ($use_root) {
1035 + $current_path = basename($current_path);
1036 + }
1037 +
1038 + if (!$use_root) {
1039 + // removing the root dir if already exists in the beginning.
1040 + $raw_name = preg_replace($root_dir_regex, '', $current_path);
1041 +
1042 + if ($raw_name && is_multisite() && ($blog_id = get_current_blog_id()) != 1) {
1043 + $folder = "sites/{$blog_id}/";
1044 + if (strpos($raw_name, $folder) === 0) return $raw_name;
1045 +
1046 + return "$folder$raw_name";
1047 + }
1048 +
1049 + return $raw_name;
1050 + }
1051 +
619 1052 // skip adding root dir if it's already added.
620 - if ( !empty( $root_dir ) && strpos($current_path, $root_dir) !== 0 ) {
621 - return $root_dir . '/' . $current_path;
1053 + if (!empty($root_dir) && !preg_match($root_dir_regex, $current_path)) {
1054 + return $root_dir . '/' . trim($current_path, '/ ');
622 1055 }
623 1056
624 1057 return $current_path;
625 1058 }
@@ -627,20 +1060,25 @@
627 1060 /**
628 1061 * @param $content
629 1062 * @return mixed
630 1063 */
631 - public function the_content_filter( $content ) {
1064 + public function the_content_filter($content) {
632 1065
633 - if ( $upload_data = wp_upload_dir() ) {
1066 + if ($upload_data = wp_upload_dir()) {
634 1067
635 - if ( !empty( $upload_data['baseurl'] ) && !empty( $content ) ) {
636 - $baseurl = preg_replace('/https?:\/\//','',$upload_data['baseurl']);
637 - $root_dir = trim( $this->get( 'sm.root_dir' ), '/ ' ); // Remove any forward slash and empty space.
638 - $root_dir = !empty( $root_dir ) ? $root_dir . '/' : false;
1068 + if (!empty($upload_data['url']) && !empty($content)) {
1069 + $url = preg_replace('/https?:\/\//', '', $upload_data['url']);
1070 +
1071 + $root_dir = trim($this->get('sm.root_dir'), '/ '); // Remove any forward slash and empty space.
1072 + $root_dir = apply_filters("wp_stateless_handle_root_dir", $root_dir);
1073 + $root_dir = !empty($root_dir) ? $root_dir . '/' : false;
639 1074 $image_host = $this->get_gs_host();
640 1075 $file_ext = $this->replaceable_file_types();
641 - $content = preg_replace( '/(href|src)=(\'|")(https?:\/\/'.str_replace('/', '\/', $baseurl).')\/(.+?)('.$file_ext.')(\'|")/i',
642 - '$1=$2'.$image_host.'/'.($root_dir?$root_dir:'').'$4$5$6', $content);
1076 + $content = preg_replace(
1077 + '/(href|src)=(\'|")(https?:\/\/' . str_replace('/', '\/', $url) . ')\/(.+?)(' . $file_ext . ')(\'|")/i',
1078 + '$1=$2' . $image_host . '/' . ($root_dir ? $root_dir : '') . '$4$5$6',
1079 + $content
1080 + );
643 1081 }
644 1082 }
645 1083
646 1084 return $content;
@@ -647,11 +1085,11 @@
647 1085 }
648 1086
649 1087 /**
650 1088 * Return file types supported by File URL Replacement.
651 - *
1089 + * @return string
652 1090 */
653 - public function replaceable_file_types(){
1091 + public function replaceable_file_types() {
654 1092 $types = $this->get('sm.body_rewrite_types');
655 1093
656 1094 // Removing extra space.
657 1095 $types = trim($types);
@@ -662,30 +1100,30 @@
662 1100 }
663 1101
664 1102 /**
665 1103 * Copied from https://developer.wordpress.org/reference/functions/get_metadata/
666 - *
1104 + *
667 1105 * @param $value null unless other filter hooked in this function.
668 1106 * @param $object_id post id
669 - * @param $meta_key
1107 + * @param $meta_key
670 1108 * @param $single
671 1109 * @return mixed
672 1110 */
673 - public function post_metadata_filter($value, $object_id, $meta_key, $single){
674 - if(empty($value)){
1111 + public function post_metadata_filter($value, $object_id, $meta_key, $single) {
1112 + if (empty($value)) {
675 1113 $meta_type = 'post';
676 1114 $transient_key = "stateless_{$meta_type}_meta";
677 -
1115 +
678 1116 $meta_cache = wp_cache_get($object_id, $transient_key);
679 - if(empty($meta_cache)){
1117 + if (empty($meta_cache)) {
680 1118 $meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
681 1119
682 - if ( !$meta_cache ) {
683 - $meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
1120 + if (!$meta_cache) {
1121 + $meta_cache = update_meta_cache($meta_type, array($object_id));
684 1122 $meta_cache = $meta_cache[$object_id];
685 1123 }
686 -
687 - foreach($meta_cache as $key => $meta){
1124 +
1125 + foreach ($meta_cache as $key => $meta) {
688 1126 $meta_cache[$key] = array_map('maybe_unserialize', $meta_cache[$key]);
689 1127 }
690 1128
691 1129 $meta_cache = $this->convert_to_gs_link($meta_cache);
@@ -690,24 +1128,23 @@
690 1128
691 1129 $meta_cache = $this->convert_to_gs_link($meta_cache);
692 1130 wp_cache_set($object_id, $meta_cache, $transient_key);
693 1131 }
694 -
695 - if ( ! $meta_key ) {
1132 +
1133 + if (!$meta_key) {
696 1134 return $meta_cache;
697 1135 }
698 -
699 - if ( isset($meta_cache[$meta_key]) ) {
1136 +
1137 + if (isset($meta_cache[$meta_key])) {
700 1138 return $meta_cache[$meta_key];
701 1139 }
702 -
703 - // in case no metadata is found return what was passed in $value.
1140 +
1141 + // in case no metadata is found return what was passed in $value.
704 1142 // $value most of the time is null.
705 1143 return $value;
706 1144 }
707 1145
708 1146 return $this->convert_to_gs_link($value);
709 -
710 1147 }
711 1148
712 1149 /**
713 1150 * Replace all image link with gs link and return only if meta modified.
@@ -712,24 +1149,26 @@
712 1149 /**
713 1150 * Replace all image link with gs link and return only if meta modified.
714 1151 *
715 1152 * @param $meta
1153 + * @param $return
716 1154 * @return mixed or null when not changed.
717 1155 */
718 - public function convert_to_gs_link($meta){
1156 + public function convert_to_gs_link($meta, $return = false) {
719 1157 $updated = $meta;
720 - if ( $meta && $upload_data = wp_upload_dir() ) {
721 - if ( !empty( $upload_data['baseurl'] ) && !empty( $meta ) ) {
722 - $baseurl = preg_replace('/https?:\/\//','',$upload_data['baseurl']);
723 - $root_dir = trim( $this->get( 'sm.root_dir' ), '/ ' ); // Remove any forward slash and empty space.
724 - $root_dir = !empty( $root_dir ) ? $root_dir . '/': false;
725 - $image_host = $this->get_gs_host().'/'.($root_dir?$root_dir:'');
1158 + if ($meta && $upload_data = wp_upload_dir()) {
1159 + if (!empty($upload_data['url']) && !empty($meta)) {
1160 + $url = preg_replace('/https?:\/\//', '', $upload_data['url']);
1161 + $root_dir = trim($this->get('sm.root_dir'), '/ '); // Remove any forward slash and empty space.
1162 + $root_dir = apply_filters("wp_stateless_handle_root_dir", $root_dir);
1163 + $root_dir = !empty($root_dir) ? $root_dir . '/' : false;
1164 + $image_host = $this->get_gs_host() . '/' . ($root_dir ? $root_dir : '');
726 1165 $file_ext = $this->replaceable_file_types();
727 - $updated = $this->_convert_to_gs_link($meta, $image_host, $baseurl, $file_ext);
1166 + $updated = $this->_convert_to_gs_link($meta, $image_host, $url, $file_ext);
728 1167 }
729 1168 }
730 1169
731 - if($updated == $meta){
1170 + if ($updated == $meta && !$return) {
732 1171 return null; // Not changed.
733 1172 }
734 1173 return $updated;
735 1174 }
@@ -737,69 +1176,54 @@
737 1176 /**
738 1177 * Replace all image link with gs link
739 1178 *
740 1179 * @param $meta
741 - * @return mixed
1180 + * @param $image_host
1181 + * @param $url
1182 + * @param $file_ext
1183 + * @return array|null|string|string[]
742 1184 */
743 - public function _convert_to_gs_link($meta, $image_host, $baseurl, $file_ext){
744 - if(is_array($meta)){
1185 + public function _convert_to_gs_link($meta, $image_host, $url, $file_ext) {
1186 + if (is_array($meta)) {
745 1187 foreach ($meta as $key => $value) {
746 - $meta[$key] = $this->_convert_to_gs_link($value, $image_host, $baseurl, $file_ext);
1188 + $meta[$key] = $this->_convert_to_gs_link($value, $image_host, $url, $file_ext);
747 1189 }
748 1190 return $meta;
749 - } elseif (is_object($meta) && $meta instanceof \stdClass ) {
1191 + } elseif (is_object($meta) && $meta instanceof \stdClass) {
750 1192 foreach (get_object_vars($meta) as $key => $value) {
751 - $meta->{$key} = $this->_convert_to_gs_link($value, $image_host, $baseurl, $file_ext);
1193 + $meta->{$key} = $this->_convert_to_gs_link($value, $image_host, $url, $file_ext);
752 1194 }
753 1195 return $meta;
754 - } elseif(is_string($meta)){
755 - return preg_replace( '/(https?:\/\/'.str_replace('/', '\/', $baseurl).')\/(.+?)(' . $file_ext . ')/i', $image_host.'$2$3', $meta);
1196 + } elseif (is_string($meta)) {
1197 + return preg_replace('/(https?:\/\/' . str_replace('/', '\/', $url) . ')\/(.+?)(' . $file_ext . ')/i', $image_host . '$2$3', $meta);
756 1198 }
757 1199
758 1200 return $meta;
759 1201 }
760 1202
761 -
762 1203 /**
763 - * @param $links
764 - * @param $file
765 - * @return mixed
766 - */
767 - public function plugin_action_links( $links, $file ) {
768 -
769 - if ($file == plugin_basename( dirname( __DIR__ ) . '/wp-stateless-media.php' ) ) {
770 - $settings_link = '<a href="'. '' .'">'.__( 'Settings' , 'ssd').'</a>';
771 - array_unshift( $links, $settings_link );
772 - }
773 -
774 - if ($file == plugin_basename( dirname( __DIR__ ) . '/wp-stateless.php' ) ) {
775 - $settings_link = '<a href="'. '' .'">'.__( 'Settings' , 'ssd').'</a>';
776 - array_unshift( $links, $settings_link );
777 - }
778 -
779 - return $links;
780 - }
781 -
782 - /**
783 1204 * Determines if plugin is loaded via mu-plugins
784 1205 * or Network Enabled.
785 1206 *
1207 + * @param bool $is_multisite
1208 + * @return bool
786 1209 * @author peshkov@UD
787 1210 */
788 - public function is_network_detected() {
1211 + public function is_network_detected($is_multisite = false) {
789 1212 /* Plugin is loaded via mu-plugins. */
790 1213
791 - if( strpos( Utility::normalize_path( $this->root_path ), Utility::normalize_path( WPMU_PLUGIN_DIR ) ) !== false ) {
1214 + if (strpos(Utility::normalize_path($this->root_path), Utility::normalize_path(WPMU_PLUGIN_DIR)) !== false) {
792 1215 return true;
793 1216 }
794 1217
795 - if( is_multisite() ) {
1218 + if (is_multisite()) {
1219 + if ($is_multisite) return true;
796 1220 /* Looks through network enabled plugins to see if our one is there. */
797 1221 foreach (wp_get_active_network_plugins() as $path) {
798 1222 // Trying again using readlink in case it's a symlink file.
799 1223 // boot_file is already solved.
800 1224 // wp_normalize_path is helpfull in windows.
801 - if (wp_normalize_path($this->boot_file) == wp_normalize_path($path) || (is_link($path) AND $this->boot_file == readlink($path))) {
1225 + if (wp_normalize_path($this->boot_file) == wp_normalize_path($path) || (is_link($path) && $this->boot_file == readlink($path))) {
802 1226 return true;
803 1227 }
804 1228 }
805 1229 }
@@ -811,58 +1235,65 @@
811 1235 * Register scripts and styles
812 1236 */
813 1237 public function admin_init() {
814 1238 $this->show_notice_stateless_cache_busting();
815 - wp_register_style( 'wp-stateless', $this->path( 'static/styles/wp-stateless.css', 'url' ), array(), self::$version );
1239 + wp_register_style('wp-stateless', $this->path('static/styles/wp-stateless.css', 'url'), array(), self::$version);
816 1240
1241 + /**
1242 + * select2 styles
1243 + */
1244 + wp_register_style('wp-stateless-select2', $this->path('static/styles/select2.min.css', 'url'), array(), self::$version);
1245 +
817 1246 /* Attachment or upload page */
818 - wp_register_script( 'wp-stateless-uploads-js', $this->path( 'static/scripts/wp-stateless-uploads.js', 'url' ), array( 'jquery' ), self::$version );
1247 + wp_register_script('wp-stateless-uploads-js', $this->path('static/scripts/wp-stateless-uploads.js', 'url'), array('jquery'), self::$version);
1248 + wp_localize_script('wp-stateless-uploads-js', 'stateless_upload', [
1249 + 'inline_sync_nonce' => wp_create_nonce('sm_inline_sync'),
1250 + ]);
819 1251
820 - /* Setup wizard styles and scripts. */
821 - wp_register_style( 'wp-stateless-bootstrap', $this->path( 'static/styles/bootstrap.min.css', 'url' ), array(), '3.3.7' );
822 - wp_register_style( 'bootstrap-grid-v4', $this->path( 'static/styles/bootstrap-grid.min.css', 'url' ), array(), '3.3.7' );
823 - wp_register_style( 'wp-stateless-setup-wizard', $this->path( 'static/styles/wp-stateless-setup-wizard.css', 'url' ), array(), self::$version );
1252 + /* Setup wizard styles. */
1253 + // #152
1254 + // wp_register_style('wp-stateless-setup-wizard', $this->path('static/styles/wp-stateless-setup-wizard.css', 'url'), array(), self::$version);
824 1255
825 - wp_register_script( 'async.min', ud_get_stateless_media()->path( 'static/scripts/async.js', 'url' ), array(), ud_get_stateless_media()->version );
826 - wp_register_script( 'jquery.history', ud_get_stateless_media()->path( 'static/scripts/jquery.history.js', 'url' ), array( 'jquery' ), ud_get_stateless_media()->version, true );
827 - wp_register_script( 'wp-stateless-validation', ud_get_stateless_media()->path( 'static/scripts/jquery.validation.js', 'url' ), array( 'jquery' ), ud_get_stateless_media()->version, true );
828 - wp_register_script( 'wp-stateless-loading', ud_get_stateless_media()->path( 'static/scripts/jquery.loading.js', 'url' ), array( 'jquery' ), ud_get_stateless_media()->version, true );
829 - wp_register_script( 'wp-stateless-comboBox', ud_get_stateless_media()->path( 'static/scripts/jquery.wp-stateless-combo-box.js', 'url' ), array( 'jquery' ), ud_get_stateless_media()->version, true );
830 - wp_register_script( 'wp-stateless-setup', ud_get_stateless_media()->path( 'static/scripts/wp-stateless-setup.js', 'url' ), array( 'jquery-ui-core', 'wp-api', 'jquery.history' ), ud_get_stateless_media()->version, true );
831 - wp_localize_script( 'wp-stateless-setup', 'stateless_l10n', $this->get_l10n_data() );
1256 + wp_register_script('wp-stateless-select2', ud_get_stateless_media()->path('static/scripts/select2.min.js', 'url'), array('jquery'), self::$version, true);
832 1257
833 - wp_register_script( 'wp-stateless-setup-wizard-js', ud_get_stateless_media()->path( 'static/scripts/wp-stateless-setup-wizard.js', 'url' ), array( 'jquery', 'wp-api', 'async.min', 'wp-stateless-setup', 'wp-stateless-comboBox', 'wp-stateless-validation', 'wp-stateless-loading' ), ud_get_stateless_media()->version, true );
1258 + /* Stateless settings page */
1259 + wp_register_script('wp-stateless-settings', ud_get_stateless_media()->path('static/scripts/wp-stateless-settings.js', 'url'), array('clipboard'), self::$version);
1260 + wp_localize_script('wp-stateless-settings', 'stateless_l10n', $this->get_l10n_data());
834 1261
1262 + wp_register_style('wp-stateless-settings', $this->path('static/styles/wp-stateless-settings.css', 'url'), array(), self::$version);
1263 + wp_register_style('wp-stateless-addons', $this->path('static/styles/wp-stateless-addons.css', 'url'), array(), self::$version);
1264 + wp_register_style('wp-stateless-status', $this->path('static/styles/wp-stateless-status.css', 'url'), array(), self::$version);
835 1265
836 - /* Stateless settings page */
837 - wp_register_script( 'wp-stateless-settings', ud_get_stateless_media()->path( 'static/scripts/wp-stateless-settings.js', 'url' ), array(), ud_get_stateless_media()->version );
838 - wp_localize_script( 'wp-stateless-settings', 'stateless_l10n', $this->get_l10n_data() );
839 -
840 - wp_register_style( 'wp-stateless-settings', $this->path( 'static/styles/wp-stateless-settings.css', 'url' ), array(), self::$version );
1266 + // Sync tab
1267 + wp_register_script('wp-stateless', ud_get_stateless_media()->path('static/scripts/wp-stateless.js', 'url'), array('jquery-ui-core', 'wp-stateless-settings', 'wp-api-request'), self::$version, true);
841 1268
842 - // Sync tab
843 - if ( wp_script_is( 'jquery-ui-widget', 'registered' ) ){
844 - wp_register_script( 'jquery-ui-progressbar', ud_get_stateless_media()->path('static/scripts/jquery-ui/jquery.ui.progressbar.min.js', 'url'), array( 'jquery-ui-core', 'jquery-ui-widget' ), '1.8.6' );
845 - }
846 - else{
847 - wp_register_script( 'jquery-ui-progressbar', ud_get_stateless_media()->path( 'static/scripts/jquery-ui/jquery.ui.progressbar.min.1.7.2.js', 'url' ), array( 'jquery-ui-core' ), '1.7.2' );
848 - }
849 - wp_register_script( 'wp-stateless-angular', ud_get_stateless_media()->path( 'static/scripts/angular.min.js', 'url' ), array(), '1.5.0', true );
850 - wp_register_script( 'wp-stateless', ud_get_stateless_media()->path( 'static/scripts/wp-stateless.js', 'url' ), array( 'jquery-ui-core', 'wp-stateless-settings' ), ud_get_stateless_media()->version, true );
851 -
852 - wp_localize_script( 'wp-stateless', 'stateless_l10n', $this->get_l10n_data() );
1269 + wp_localize_script('wp-stateless', 'stateless_l10n', $this->get_l10n_data());
853 1270 wp_localize_script('wp-stateless', 'wp_stateless_configs', array(
854 1271 'WP_DEBUG' => defined('WP_DEBUG') ? WP_DEBUG : false,
1272 + 'REST_API_TOKEN' => Utility::generate_jwt_token(['user_id' => get_current_user_id()], DAY_IN_SECONDS),
1273 + 'api_root' => apply_filters( 'wp_stateless_rest_api_root', '' ),
1274 + 'ajaxurl' => admin_url( 'admin-ajax.php' ),
1275 + 'stateless_check_ajax_nonce' => wp_create_nonce('stateless_check_ajax'),
1276 + 'text_ok' => __('Ok', ud_get_stateless_media()->domain),
1277 + 'text_fail' => __('Fail', ud_get_stateless_media()->domain),
855 1278 ));
856 -
1279 +
857 1280 $settings = ud_get_stateless_media()->get('sm');
858 - if(defined('WP_STATELESS_MEDIA_JSON_KEY') && WP_STATELESS_MEDIA_JSON_KEY){
1281 + $settings['wildcards'] = $this->settings->wildcards;
1282 + $settings['network_admin'] = is_network_admin();
1283 + $settings['is_multisite'] = is_multisite();
1284 + if (defined('WP_STATELESS_MEDIA_JSON_KEY') && WP_STATELESS_MEDIA_JSON_KEY) {
859 1285 $settings['key_json'] = "Currently configured via a constant.";
860 1286 }
861 1287 wp_localize_script('wp-stateless', 'wp_stateless_settings', $settings);
862 - wp_localize_script('wp-stateless', 'wp_stateless_compatibility', Module::get_modules());
863 - wp_register_style( 'jquery-ui-regenthumbs', ud_get_stateless_media()->path( 'static/scripts/jquery-ui/redmond/jquery-ui-1.7.2.custom.css', 'url' ), array(), '1.7.2' );
864 1288
1289 + // Batch processes tab
1290 + wp_register_script('wp-stateless-batch', ud_get_stateless_media()->path('static/scripts/wp-stateless-batch.js', 'url'), array('wp-api-request'), self::$version, true);
1291 + wp_localize_script('wp-stateless-batch', 'wp_stateless_batch', array(
1292 + 'REST_API_TOKEN' => Utility::generate_jwt_token(['user_id' => get_current_user_id()], DAY_IN_SECONDS),
1293 + 'is_running' => BatchTaskManager::instance()->is_running(),
1294 + 'api_root' => apply_filters( 'wp_stateless_rest_api_root', '' ),
1295 + ));
865 1296 }
866 1297
867 1298 /**
868 1299 * Get_l10n_data
@@ -869,10 +1300,10 @@
869 1300 *
870 1301 * @param string $value
871 1302 * @return mixed
872 1303 */
873 - public function get_l10n_data($value=''){
874 - include ud_get_stateless_media()->path( 'l10n.php', 'dir');
1304 + public function get_l10n_data($value = '') {
1305 + include ud_get_stateless_media()->path('l10n.php', 'dir');
875 1306 return $l10n;
876 1307 }
877 1308
878 1309 /**
@@ -879,24 +1310,20 @@
879 1310 * Admin Scripts
880 1311 *
881 1312 * @param $hook
882 1313 */
883 - public function admin_enqueue_scripts( $hook ) {
1314 + public function admin_enqueue_scripts($hook) {
884 1315
885 - switch( $hook ) {
1316 + switch ($hook) {
886 1317
887 1318 case 'options-media.php':
888 - //wp_enqueue_script( 'wp-api' );
1319 + wp_enqueue_style('wp-stateless');
1320 + break;
889 1321
890 - wp_enqueue_style( 'wp-stateless');
891 - wp_enqueue_script( 'wp-stateless-setup' );
892 - break;
893 -
894 1322 case 'upload.php':
1323 + wp_enqueue_style('wp-stateless');
1324 + wp_enqueue_script('wp-stateless-uploads-js');
895 1325
896 - wp_enqueue_style( 'wp-stateless');
897 - wp_enqueue_script( 'wp-stateless-uploads-js' );
898 -
899 1326 break;
900 1327
901 1328 case 'post.php':
902 1329
@@ -901,57 +1328,60 @@
901 1328 case 'post.php':
902 1329
903 1330 global $post;
904 1331
905 - if ( $post->post_type == 'attachment' ) {
906 - wp_enqueue_style( 'wp-stateless');
907 - wp_enqueue_script( 'wp-stateless-uploads-js' );
1332 + if ($post->post_type == 'attachment') {
1333 + wp_enqueue_style('wp-stateless');
1334 + wp_enqueue_script('wp-stateless-uploads-js');
908 1335 }
909 1336
910 1337 break;
911 1338
912 - case 'media_page_stateless-setup':
1339 + // #152
1340 + // case 'media_page_stateless-setup':
913 1341 case 'settings_page_stateless-setup':
914 - wp_enqueue_style( 'wp-stateless');
915 - wp_enqueue_style( 'wp-stateless-bootstrap' );
916 - wp_enqueue_style( 'wp-stateless-setup-wizard' );
917 -
918 - wp_enqueue_script( 'async.min' );
919 - wp_enqueue_script( 'jquery.history' );
920 - wp_enqueue_script( 'wp-stateless-validation' );
921 - wp_enqueue_script( 'wp-stateless-loading' );
922 - wp_enqueue_script( 'wp-stateless-comboBox' );
923 - wp_enqueue_script( 'wp-stateless-setup' );
924 - wp_enqueue_script( 'wp-stateless-setup-wizard-js' );
1342 + wp_enqueue_style('wp-stateless');
1343 + // #152
1344 + // wp_enqueue_style('wp-stateless-setup-wizard');
925 1345 break;
926 1346 case 'media_page_stateless-settings':
927 1347 case 'settings_page_stateless-settings':
928 - wp_enqueue_style( 'wp-stateless');
929 - wp_enqueue_script( 'wp-stateless-settings' );
930 - wp_enqueue_style( 'bootstrap-grid-v4' );
931 - wp_enqueue_style( 'wp-stateless-settings' );
932 -
1348 + wp_enqueue_style('wp-stateless');
1349 + wp_enqueue_style('wp-stateless-select2');
1350 + wp_enqueue_script('wp-stateless-settings');
1351 + wp_enqueue_script('wp-stateless-select2');
1352 + wp_enqueue_style('wp-stateless-settings');
1353 + wp_enqueue_style('wp-stateless-addons');
1354 + wp_enqueue_style('wp-stateless-status');
1355 + wp_enqueue_style( 'media-views' );
1356 +
933 1357 // Sync tab
934 - wp_enqueue_script( 'jquery-ui-progressbar' );
935 - wp_enqueue_script( 'wp-stateless-angular' );
936 - wp_enqueue_script( 'wp-stateless' );
937 - wp_enqueue_style( 'jquery-ui-regenthumbs' );
1358 + wp_enqueue_script('wp-stateless');
938 1359
1360 + // Data updates
1361 + wp_enqueue_script('jquery-ui-dialog');
1362 + wp_enqueue_style('wp-jquery-ui-dialog');
1363 + wp_enqueue_script('wp-stateless-batch');
1364 +
1365 + wp_enqueue_style('wp-pointer');
1366 + wp_enqueue_script('wp-pointer');
1367 +
939 1368 $data = array(
940 - 'key' => 'stateless-cache-busting',
941 - 'class' => 'notice',
942 - 'title' => sprintf( __( "Stateless mode enables and requires the Cache-Busting option.", ud_get_stateless_media()->domain ) ),
943 - 'message' => sprintf( __("WordPress looks at local files to prevent files with the same filenames.
944 - Since Stateless mode bypasses this check, there is a potential for files to be stored with the same file name. We enforce the Cache-Busting option to prevent this.
945 - Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain),"https://wp-stateless.github.io/docs/constants/#wp_stateless_media_cache_busting", "WP_STATELESS_MEDIA_CACHE_BUSTING" ),
946 - );
1369 + 'key' => 'stateless-cache-busting',
1370 + 'class' => 'notice',
1371 + 'title' => sprintf(__("Stateless and Ephemeral modes enables and requires the Cache-Busting option.", ud_get_stateless_media()->domain)),
1372 + 'message' => sprintf(__("WordPress looks at local files to prevent files with the same filenames.
1373 + Since Stateless mode bypasses this check, there is a potential for files to be stored with the same file name. We enforce the Cache-Busting option to prevent this.
1374 + Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain), ud_get_stateless_media()->get_docs_page_url('docs/constants/#wpstatelessmediacachebusting'), "WP_STATELESS_MEDIA_CACHE_BUSTING"),
1375 + );
947 1376 echo "<script id='template-stateless-cache-busting' type='text/html'>";
948 - include ud_get_stateless_media()->path( '/static/views/error-notice.php', 'dir' );
1377 + include ud_get_stateless_media()->path('/static/views/error-notice.php', 'dir');
949 1378 echo "</script>";
1379 +
950 1380 break;
951 - default: break;
1381 + default:
1382 + break;
952 1383 }
953 -
954 1384 }
955 1385
956 1386 /**
957 1387 * Add Attributes to media HTML
@@ -961,20 +1391,19 @@
961 1391 * @param $attachment
962 1392 * @param $size
963 1393 * @return mixed
964 1394 */
965 - public function wp_get_attachment_image_attributes( $attr, $attachment, $size = null ) {
966 -
967 - $sm_cloud = get_post_meta( $attachment->ID, 'sm_cloud', true );
968 - if( is_array( $sm_cloud ) && !empty( $sm_cloud[ 'name' ] ) ) {
969 - $attr[ 'class' ] = $attr[ 'class' ] . ' wp-stateless-item';
970 - $attr[ 'data-image-size' ] = is_array( $size ) ? implode( 'x', $size ) : $size;
971 - $attr[ 'data-stateless-media-bucket' ] = isset( $sm_cloud[ 'bucket' ] ) ? $sm_cloud[ 'bucket' ] : false;
972 - $attr[ 'data-stateless-media-name' ] = $sm_cloud[ 'name' ];
1395 + public function wp_get_attachment_image_attributes($attr, $attachment, $size = null) {
1396 +
1397 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment->ID);
1398 + if (is_array($sm_cloud) && !empty($sm_cloud['name'])) {
1399 + $attr['class'] = $attr['class'] . ' wp-stateless-item';
1400 + $attr['data-image-size'] = is_array($size) ? implode('x', $size) : $size;
1401 + $attr['data-stateless-media-bucket'] = isset($sm_cloud['bucket']) ? $sm_cloud['bucket'] : false;
1402 + $attr['data-stateless-media-name'] = $sm_cloud['name'];
973 1403 }
974 1404
975 1405 return $attr;
976 -
977 1406 }
978 1407
979 1408 /**
980 1409 * Adds filter link to Media Library table.
@@ -981,10 +1410,10 @@
981 1410 *
982 1411 * @param $views
983 1412 * @return mixed
984 1413 */
985 - public function views_upload( $views ) {
986 - $views['stateless'] = '<a href="#">' . __( 'Stateless Media' ) . '</a>';
1414 + public function views_upload($views) {
1415 + $views['stateless'] = '<a href="#">' . __('Stateless Media') . '</a>';
987 1416 return $views;
988 1417 }
989 1418
990 1419 /**
@@ -994,11 +1423,11 @@
994 1423 * @param integer $id
995 1424 * @param string $size
996 1425 * @return mixed $false
997 1426 */
998 - public function image_downsize( $false = false, $id, $size ) {
1427 + public function image_downsize($false, $id, $size) {
999 1428
1000 - if ( !isset( $this->client ) || !$this->client || is_wp_error( $this->client ) ) {
1429 + if ((!isset($this->client) || !$this->client || is_wp_error($this->client)) && $this->get('sm.mode') !== 'stateless') {
1001 1430 return $false;
1002 1431 }
1003 1432
1004 1433 /**
@@ -1003,9 +1432,9 @@
1003 1432
1004 1433 /**
1005 1434 * Check if enabled
1006 1435 */
1007 - if ( $this->get( 'sm.mode' ) !== 'cdn' && $this->get( 'sm.mode' ) !== 'stateless' ) {
1436 + if (!in_array($this->get('sm.mode'), array('cdn', 'stateless', 'ephemeral'))) {
1008 1437 return $false;
1009 1438 }
1010 1439
1011 1440 /** Start determine remote file */
@@ -1014,19 +1443,17 @@
1014 1443 $width = $height = 0;
1015 1444 $is_intermediate = false;
1016 1445
1017 1446 //** try for a new style intermediate size */
1018 - if ( $intermediate = image_get_intermediate_size( $id, $size ) ) {
1019 - if(!empty( $intermediate['gs_link'] )){
1447 + if ($intermediate = image_get_intermediate_size($id, $size)) {
1448 + if (!empty($intermediate['gs_link'])) {
1020 1449 $img_url = $intermediate['gs_link'];
1021 - }
1022 - else if(!empty( $intermediate['url'] )){
1450 + } else if (!empty($intermediate['url'])) {
1023 1451 $img_url = $intermediate['url'];
1024 - }
1025 - else{
1452 + } else {
1026 1453 $img_url = dirname($img_url) . $intermediate['file'];
1027 1454 }
1028 -
1455 +
1029 1456 $width = $intermediate['width'];
1030 1457 $height = $intermediate['height'];
1031 1458 $is_intermediate = true;
1032 1459 }
@@ -1035,18 +1462,18 @@
1035 1462 * maybe try to get images info from sm_cloud
1036 1463 * this case may happen when no local files
1037 1464 * @author korotkov@ud
1038 1465 */
1039 - if ( !$width && !$height ) {
1040 - $sm_cloud = get_post_meta( $id, 'sm_cloud', true );
1041 - if ( is_string($size) && !empty( $sm_cloud['sizes'] ) && !empty( $sm_cloud['sizes'][$size] ) ) {
1466 + if (!$width && !$height) {
1467 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $id, true);
1468 + if (is_string($size) && !empty($sm_cloud['sizes']) && !empty($sm_cloud['sizes'][$size])) {
1042 1469 global $_wp_additional_image_sizes;
1043 1470
1044 - $img_url = !empty( $sm_cloud['sizes'][$size]['fileLink'] ) ? $sm_cloud['sizes'][$size]['fileLink'] : $img_url;
1471 + $img_url = !empty($sm_cloud['sizes'][$size]['fileLink']) ? $sm_cloud['sizes'][$size]['fileLink'] : $img_url;
1045 1472
1046 - if ( !empty( $_wp_additional_image_sizes[ $size ] ) ) {
1047 - $width = !empty( $_wp_additional_image_sizes[ $size ]['width'] ) ? $_wp_additional_image_sizes[ $size ]['width'] : $width;
1048 - $height = !empty( $_wp_additional_image_sizes[ $size ]['height'] ) ? $_wp_additional_image_sizes[ $size ]['height'] : $height;
1473 + if (!empty($_wp_additional_image_sizes[$size])) {
1474 + $width = !empty($_wp_additional_image_sizes[$size]['width']) ? $_wp_additional_image_sizes[$size]['width'] : $width;
1475 + $height = !empty($_wp_additional_image_sizes[$size]['height']) ? $_wp_additional_image_sizes[$size]['height'] : $height;
1049 1476 }
1050 1477
1051 1478 $is_intermediate = true;
1052 1479 }
@@ -1051,9 +1478,9 @@
1051 1478 $is_intermediate = true;
1052 1479 }
1053 1480 }
1054 1481
1055 - if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
1482 + if (!$width && !$height && isset($meta['width'], $meta['height'])) {
1056 1483
1057 1484 //** any other type: use the real image */
1058 1485 $width = $meta['width'];
1059 1486 $height = $meta['height'];
@@ -1059,14 +1486,14 @@
1059 1486 $height = $meta['height'];
1060 1487 }
1061 1488
1062 1489
1063 - if ( $img_url) {
1490 + if ($img_url) {
1064 1491
1065 1492 //** we have the actual image size, but might need to further constrain it if content_width is narrower */
1066 - list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
1493 + list($width, $height) = image_constrain_size_for_editor($width, $height, $size);
1067 1494 $img_url = apply_filters('wp_stateless_bucket_link', $img_url);
1068 - return array( $img_url, $width, $height, $is_intermediate );
1495 + return array($img_url, $width, $height, $is_intermediate);
1069 1496 }
1070 1497
1071 1498
1072 1499 /**
@@ -1072,9 +1499,8 @@
1072 1499 /**
1073 1500 * All other cases work as usually
1074 1501 */
1075 1502 return $false;
1076 -
1077 1503 }
1078 1504
1079 1505 /**
1080 1506 * Extends metadata by adding GS information.
@@ -1083,34 +1509,100 @@
1083 1509 * @param $metadata
1084 1510 * @param $attachment_id
1085 1511 * @return array|mixed
1086 1512 */
1087 - public function wp_get_attachment_metadata( $metadata, $attachment_id ) {
1513 + public function wp_get_attachment_metadata($metadata, $attachment_id) {
1514 + global $default_dir;
1515 + $default_dir = false;
1088 1516 /* Determine if the media file has GS data at all. */
1089 - $sm_cloud = get_post_meta( $attachment_id, 'sm_cloud', true );
1517 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment_id, true);
1090 1518 // If metadata not passed the get metadata from post meta.
1091 - if(empty($metadata)){
1092 - $metadata = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
1519 + if (empty($metadata)) {
1520 + $metadata = get_post_meta($attachment_id, '_wp_attachment_metadata', true);
1093 1521 }
1094 1522
1095 - if( is_array( $metadata ) && is_array( $sm_cloud ) && !empty( $sm_cloud[ 'fileLink' ] ) ) {
1096 - $metadata[ 'gs_link' ] = apply_filters('wp_stateless_bucket_link', $sm_cloud[ 'fileLink' ]);
1097 - $metadata[ 'gs_name' ] = isset( $sm_cloud[ 'name' ] ) ? $sm_cloud[ 'name' ] : false;
1098 - $metadata[ 'gs_bucket' ] = isset( $sm_cloud[ 'bucket' ] ) ? $sm_cloud[ 'bucket' ] : false;
1099 - if( !empty( $metadata[ 'sizes' ] ) && is_array( $metadata[ 'sizes' ] ) ) {
1100 - foreach( $metadata[ 'sizes' ] as $k => $v ) {
1101 - if( !empty( $sm_cloud[ 'sizes' ][ $k ][ 'name' ] ) ) {
1102 - $metadata['sizes'][$k]['gs_name'] = $sm_cloud[ 'sizes' ][ $k ][ 'name' ];
1103 - $metadata['sizes'][$k]['gs_link'] = apply_filters('wp_stateless_bucket_link', $sm_cloud[ 'sizes' ][ $k ][ 'fileLink' ]);
1523 + if (empty($metadata)) {
1524 + $metadata = [];
1525 + }
1526 +
1527 + if (is_array($metadata) && is_array($sm_cloud) && !empty($sm_cloud['fileLink'])) {
1528 + $metadata['gs_link'] = apply_filters('wp_stateless_bucket_link', $sm_cloud['fileLink']);
1529 + $metadata['gs_name'] = isset($sm_cloud['name']) ? $sm_cloud['name'] : false;
1530 + $metadata['gs_bucket'] = isset($sm_cloud['bucket']) ? $sm_cloud['bucket'] : false;
1531 + if (!empty($metadata['sizes']) && is_array($metadata['sizes'])) {
1532 + foreach ($metadata['sizes'] as $k => $v) {
1533 + if (!empty($sm_cloud['sizes'][$k]['name'])) {
1534 + $metadata['sizes'][$k]['gs_name'] = $sm_cloud['sizes'][$k]['name'];
1535 + $metadata['sizes'][$k]['gs_link'] = apply_filters('wp_stateless_bucket_link', $sm_cloud['sizes'][$k]['fileLink']);
1104 1536 }
1105 1537 }
1106 1538 }
1107 1539 }
1540 + if (is_multisite() && !empty($metadata['file'])) {
1541 + if ($this->get('sm.mode') == 'stateless') {
1542 + $default_dir = true;
1543 + $uploads = wp_get_upload_dir();
1544 + $default_dir = false;
1108 1545
1546 + $file_path_fix = $uploads['basedir'] . "/{$metadata['file']}";
1547 + if (file_exists($file_path_fix)) {
1548 + $metadata['file'] = "{$metadata['file']}";
1549 + }
1550 + } else {
1551 + $uploads = wp_get_upload_dir();
1552 + $blog_id = get_current_blog_id();
1553 + $file_path_fix = $uploads['basedir'] . "/sites/$blog_id/{$metadata['file']}";
1554 + if (file_exists($file_path_fix)) {
1555 + $metadata['file'] = "sites/$blog_id/{$metadata['file']}";
1556 + }
1557 + }
1558 + } elseif ( empty($sm_cloud) && $this->get('sm.mode') == 'stateless' && isset($metadata['file']) ) {
1559 + $default_dir = true;
1560 + $uploads = wp_get_upload_dir();
1561 + $default_dir = false;
1562 +
1563 + $file_path_fix = $uploads['basedir'] . "/{$metadata['file']}";
1564 + if (file_exists($file_path_fix)) {
1565 + $metadata['file'] = "{$metadata['file']}";
1566 + }
1567 + }
1568 +
1109 1569 return $metadata;
1110 1570 }
1111 1571
1112 1572 /**
1573 + *
1574 + * @param $file
1575 + * @param $attachment_id
1576 + * @return string
1577 + */
1578 + public function get_attached_file($file, $attachment_id) {
1579 + global $default_dir;
1580 +
1581 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment_id);
1582 + $_file = get_post_meta($attachment_id, '_wp_attached_file', true);
1583 +
1584 + /* Determine if the media file has GS data at all. */
1585 + if (is_multisite() && $_file) {
1586 + $blog_id = get_current_blog_id();
1587 + $uploads = wp_get_upload_dir();
1588 + $_file = apply_filters('wp_stateless_file_name', $_file, false);
1589 + $file_path_fix = $uploads['basedir'] . "/sites/$blog_id/$_file";
1590 +
1591 + if (file_exists($file_path_fix)) {
1592 + return $file_path_fix;
1593 + }
1594 + } elseif (empty($sm_cloud) && $this->get('sm.mode') == 'stateless' && $_file) {
1595 + $default_dir = true;
1596 + $uploads = wp_get_upload_dir();
1597 + $default_dir = false;
1598 + return $uploads['basedir'] . '/' . $_file;
1599 + }
1600 +
1601 + return $file;
1602 + }
1603 +
1604 + /**
1113 1605 * Returns client object
1114 1606 * or WP_Error on failure.
1115 1607 *
1116 1608 * @author peshkov@UD
@@ -1117,24 +1609,23 @@
1117 1609 * @return object $this->client. \wpCloud\StatelessMedia\GS_Client or \WP_Error
1118 1610 */
1119 1611 public function get_client() {
1120 1612
1121 - if( null === $this->client ) {
1613 + if (null === $this->client) {
1122 1614
1123 - $key_json = get_site_option( 'sm_key_json' );
1124 - if ( empty($key_json) ) {
1125 - $key_json = $this->get( 'sm.key_json' );
1615 + $key_json = $this->get('sm.key_json');
1616 + if (empty($key_json)) {
1617 + $key_json = get_site_option('sm_key_json');
1126 1618 }
1127 1619
1128 1620 /* Try to initialize GS Client */
1129 - $this->client = GS_Client::get_instance( array(
1130 - 'bucket' => $this->get( 'sm.bucket' ),
1621 + $this->client = GS_Client::get_instance(array(
1622 + 'bucket' => $this->get('sm.bucket'),
1131 1623 'key_json' => $key_json
1132 - ) );
1624 + ));
1133 1625 }
1134 1626
1135 1627 return $this->client;
1136 -
1137 1628 }
1138 1629
1139 1630 /**
1140 1631 * Determines if we can connect to Google Storage Bucket.
@@ -1141,47 +1632,46 @@
1141 1632 *
1142 1633 * @author peshkov@UD
1143 1634 */
1144 1635 public function is_connected_to_gs() {
1636 + $trnst = get_transient('sm::is_connected_to_gs');
1145 1637
1146 - $trnst = get_transient( 'sm::is_connected_to_gs' );
1147 -
1148 - if ( empty($trnst) || false === $trnst || !isset( $trnst[ 'hash' ] ) || $trnst[ 'hash' ] != md5( serialize( $this->get( 'sm' ) ) ) ) {
1638 + if (empty($trnst) || false === $trnst || !isset($trnst['hash']) || $trnst['hash'] != md5(serialize($this->get('sm')))) {
1149 1639 $trnst = array(
1150 1640 'success' => 'true',
1151 1641 'error' => '',
1152 - 'hash' => md5( serialize( $this->get( 'sm' ) ) ),
1642 + 'hash' => md5(serialize($this->get('sm'))),
1153 1643 );
1154 1644 $client = $this->get_client();
1155 1645
1156 - if ( is_wp_error( $client ) ) {
1157 - $trnst[ 'success' ] = 'false';
1158 - $trnst[ 'error' ] = $client->get_error_message();
1646 + if (is_wp_error($client)) {
1647 + $trnst['success'] = 'false';
1648 + $trnst['error'] = $client->get_error_message();
1159 1649 } else {
1160 1650 $connected = $client->is_connected();
1161 - if( $connected !== true ) {
1162 - $trnst[ 'success' ] = 'false';
1163 - $trnst[ 'error' ] = sprintf( __( 'Could not connect to Google Storage bucket. Please, be sure that bucket with name <b>%s</b> exists.', $this->domain ), $this->get( 'sm.bucket' ) );
1651 + if ($connected !== true) {
1652 + $trnst['success'] = 'false';
1653 + $trnst['error'] = sprintf('Could not connect to Google Storage bucket. Please be sure that bucket with name <b>%s</b> exists and the access credentials are correct.', esc_html($this->get('sm.bucket')));
1164 1654
1165 - if( is_callable(array($connected, 'getHandlerContext')) && $handlerContext = $connected->getHandlerContext() ){
1166 - if(!empty($handlerContext['error'])){
1655 + if (is_callable(array($connected, 'getHandlerContext')) && $handlerContext = $connected->getHandlerContext()) {
1656 + if (!empty($handlerContext['error'])) {
1167 1657 $handlerContext['error'];
1168 - $trnst[ 'error' ] = "Could not connect to Google Storage bucket. " . make_clickable($handlerContext['error']);
1658 + $trnst['error'] = "Could not connect to Google Storage bucket. " . make_clickable($handlerContext['error']);
1169 1659 }
1170 1660 }
1171 1661
1172 - if( is_callable(array($connected, 'getErrors')) && $error = $connected->getErrors() ){
1662 + if (is_callable(array($connected, 'getErrors')) && $error = $connected->getErrors()) {
1173 1663 $error = reset($error);
1174 - if($error['reason'] == 'accessNotConfigured')
1175 - $trnst[ 'error' ] = "Could not connect to Google Storage bucket. " . make_clickable($error['message']);
1664 + if ($error['reason'] == 'accessNotConfigured')
1665 + $trnst['error'] = "Could not connect to Google Storage bucket. " . make_clickable($error['message']);
1176 1666 }
1177 1667 }
1178 1668 }
1179 - set_transient( 'sm::is_connected_to_gs', $trnst, 4 * HOUR_IN_SECONDS );
1669 + set_transient('sm::is_connected_to_gs', $trnst, 4 * HOUR_IN_SECONDS);
1180 1670 }
1181 1671
1182 - if( isset( $trnst[ 'success' ] ) && $trnst[ 'success' ] == 'false' ) {
1183 - return new \WP_Error( 'error', ( !empty( $trnst[ 'error' ] ) ? $trnst[ 'error' ] : __( 'There is an Error on connection to Google Storage.', $this->domain ) ) );
1672 + if (isset($trnst['success']) && $trnst['success'] == 'false') {
1673 + return new \WP_Error('error', (!empty($trnst['error']) ? $trnst['error'] : 'There is an Error on connection to Google Storage.'));
1184 1674 }
1185 1675
1186 1676 return true;
1187 1677 }
@@ -1190,9 +1680,9 @@
1190 1680 * Flush all plugin transients
1191 1681 *
1192 1682 */
1193 1683 public function flush_transients() {
1194 - delete_transient( 'sm::is_connected_to_gs' );
1684 + delete_transient('sm::is_connected_to_gs');
1195 1685 }
1196 1686
1197 1687 /**
1198 1688 * Plugin Activation
@@ -1198,9 +1688,9 @@
1198 1688 * Plugin Activation
1199 1689 *
1200 1690 */
1201 1691 public function activate() {
1202 - add_action( 'activated_plugin', array($this, 'redirect_to_splash'), 99 );
1692 + add_action('activated_plugin', array($this, 'redirect_to_splash'), 99);
1203 1693 $this->run_upgrade_process();
1204 1694 }
1205 1695
1206 1696 /**
@@ -1209,10 +1699,9 @@
1209 1699 * Works on even manual plugin update.
1210 1700 *
1211 1701 * @author alim@UD
1212 1702 */
1213 - public function run_install_process()
1214 - {
1703 + public function run_install_process() {
1215 1704 // calling the upgrade function because it's same as this point for fresh install or updates.
1216 1705 $this->run_upgrade_process();
1217 1706 }
1218 1707
@@ -1222,60 +1711,27 @@
1222 1711 * Works on even manual plugin update.
1223 1712 *
1224 1713 * @author alim@UD
1225 1714 */
1226 - public function run_upgrade_process()
1227 - {
1715 + public function run_upgrade_process() {
1228 1716 // Creating database on new installation.
1229 - $this->create_db();
1717 + ud_stateless_db()->create_db();
1718 +
1719 + Migrator::instance()->migrate();
1720 +
1230 1721 /**
1231 1722 * Maybe Upgrade current Version
1232 1723 */
1233 - Upgrader::call( $this->args[ 'version' ] );
1724 + Upgrader::call($this->args['version']);
1234 1725 }
1235 1726
1236 1727 /**
1237 - * Create database on plugin activation.
1238 - * @param boolean $force - whether to create db even if option exists. For debug purpose only.
1239 - */
1240 - public function create_db($force = false) {
1241 - global $wpdb;
1242 - $sm_sync_db_version = get_option( 'sm_sync_db_version' );
1243 -
1244 - if( $sm_sync_db_version && $force == false ) {
1245 - return;
1246 - }
1247 -
1248 - $table_name = $wpdb->prefix . 'sm_sync';
1249 - $charset_collate = $wpdb->get_charset_collate();
1250 -
1251 - // `expire` timestamp NULL DEFAULT NULL,
1252 - $sql = "CREATE TABLE $table_name (
1253 - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT ,
1254 - `file` varchar(255) NOT NULL ,
1255 - `status` varchar(10) NOT NULL ,
1256 - PRIMARY KEY (`id`)
1257 - ) $charset_collate;";
1258 -
1259 - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
1260 - dbDelta( $sql );
1261 -
1262 - add_option( 'sm_sync_db_version', $this->args[ 'version' ] );
1263 - }
1264 -
1265 - /**
1266 - *
1267 1728 * Delete table when blog is deleted.
1729 + *
1730 + * @param $old_site
1268 1731 */
1269 - public function wp_delete_site($old_site){
1270 - global $wpdb;
1271 -
1272 - switch_to_blog( $old_site->id );
1273 - $table_name = $wpdb->prefix . 'sm_sync';
1274 -
1275 - $sql = "DROP TABLE IF EXISTS $table_name";
1276 - $wpdb->query($sql);
1277 - restore_current_blog();
1732 + public function wp_delete_site($old_site) {
1733 + ud_stateless_db()->clear_db($old_site->id);
1278 1734 }
1279 1735
1280 1736 /**
1281 1737 * Redirect_to_splash
@@ -1281,34 +1737,38 @@
1281 1737 * Redirect_to_splash
1282 1738 *
1283 1739 * @param string $plugin
1284 1740 */
1285 - public function redirect_to_splash($plugin =''){
1286 - $this->settings = new Settings();
1741 + public function redirect_to_splash($plugin = '') {
1742 + // $this->settings = new Settings();
1287 1743
1288 - if(defined( 'WP_CLI' ) || $this->settings->get('sm.key_json') || isset($_POST['checked']) && count($_POST['checked']) > 1){
1744 + if (defined('WP_CLI') || $this->settings->get('sm.key_json') || isset($_POST['checked']) && count($_POST['checked']) > 1) {
1289 1745 return;
1290 1746 }
1291 -
1292 - if(
1293 - !$this->settings->get('sm.key_json') &&
1294 - defined('WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT') && WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT == true &&
1295 - defined('WP_STATELESS_MEDIA_HIDE_SETTINGS_PANEL') && WP_STATELESS_MEDIA_HIDE_SETTINGS_PANEL == true
1747 +
1748 + if (
1749 + !$this->settings->get('sm.key_json') &&
1750 + defined('WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT') && WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT == true &&
1751 + defined('WP_STATELESS_MEDIA_HIDE_SETTINGS_PANEL') && WP_STATELESS_MEDIA_HIDE_SETTINGS_PANEL == true
1296 1752 ) {
1297 1753 return;
1298 1754 }
1299 -
1300 - if( !$this->settings->get('sm.key_json') && defined('WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT') && WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT == true ) {
1755 +
1756 + if (!$this->settings->get('sm.key_json') && defined('WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT') && WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT == true) {
1301 1757 $url = $this->get_settings_page_url('?page=stateless-settings');
1302 - exit( wp_redirect($url));
1758 + exit(wp_redirect($url));
1303 1759 }
1304 -
1305 - if( $plugin == plugin_basename( $this->boot_file ) ) {
1306 - $url = $this->get_settings_page_url('?page=stateless-setup&step=splash-screen');
1307 - if(json_decode($this->settings->get('sm.key_json'))){
1760 +
1761 + if ($plugin == plugin_basename($this->boot_file)) {
1762 + // #152
1763 + // $url = $this->get_settings_page_url('?page=stateless-setup&step=splash-screen');
1764 + $url = $this->get_settings_page_url('?page=stateless-settings');
1765 +
1766 + if (json_decode($this->settings->get('sm.key_json'))) {
1308 1767 $url = $this->get_settings_page_url('?page=stateless-settings');
1309 1768 }
1310 - exit( wp_redirect($url));
1769 +
1770 + exit( wp_redirect($url) );
1311 1771 }
1312 1772 }
1313 1773
1314 1774 /**
@@ -1314,64 +1774,102 @@
1314 1774 /**
1315 1775 * Plugin Deactivation
1316 1776 *
1317 1777 */
1318 - public function deactivate() {}
1778 + public function deactivate() {
1779 + }
1319 1780
1320 1781 /**
1321 1782 * Show_notice_stateless_cache_busting
1322 1783 *
1323 1784 */
1324 - public function show_notice_stateless_cache_busting(){
1325 - $this->errors->add( array(
1785 + public function show_notice_stateless_cache_busting() {
1786 + $this->errors->add(array(
1326 1787 'key' => 'stateless_cache_busting',
1327 1788 'button' => 'View Settings',
1328 1789 'button_link' => admin_url('upload.php?page=stateless-settings'),
1329 - 'title' => sprintf( __( "Stateless mode now requires the Cache-Busting option.", ud_get_stateless_media()->domain ) ),
1330 - 'message' => sprintf( __("WordPress looks at local files to prevent files with the same filenames.
1331 - Since Stateless mode bypasses this check, there is a potential for files to be stored with the same file name. We enforce the Cache-Busting option to prevent this.
1332 - Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain),"https://wp-stateless.github.io/docs/constants/#wp_stateless_media_cache_busting", "WP_STATELESS_MEDIA_CACHE_BUSTING" ),
1333 - ), 'notice' );
1790 + 'title' => sprintf(__("Stateless mode now requires the Cache-Busting option.", ud_get_stateless_media()->domain)),
1791 + 'message' => sprintf(__("WordPress looks at local files to prevent files with the same filenames.
1792 + Since Stateless mode bypasses this check, there is a potential for files to be stored with the same file name. We enforce the Cache-Busting option to prevent this.
1793 + Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain), ud_get_stateless_media()->get_docs_page_url('docs/constants/#wpstatelessmediacachebusting'), "WP_STATELESS_MEDIA_CACHE_BUSTING"),
1794 + ), 'notice');
1334 1795 }
1335 1796
1336 1797 /**
1337 1798 * Filter for wp_get_attachment_url();
1338 - *
1339 1799 * @param string $url
1340 1800 * @param string $post_id
1341 1801 * @return mixed|null|string
1342 1802 */
1343 - public function wp_get_attachment_url( $url = '', $post_id = '' ) {
1344 - $sm_cloud = get_post_meta( $post_id, 'sm_cloud', 1 );
1345 - if( is_array( $sm_cloud ) && !empty( $sm_cloud[ 'fileLink' ] ) ) {
1346 - $_url = parse_url($sm_cloud[ 'fileLink' ]);
1347 - $url = !isset($_url['scheme']) ? ( 'https:' . $sm_cloud[ 'fileLink' ] ) : $sm_cloud[ 'fileLink' ];
1348 - return apply_filters('wp_stateless_bucket_link', $url);
1803 + public function wp_get_attachment_url($url = '', $post_id = '') {
1804 + global $default_dir;
1805 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $post_id);
1806 + if (is_array($sm_cloud) && !empty($sm_cloud['fileLink'])) {
1807 + $_url = parse_url($sm_cloud['fileLink']);
1808 + $url = !isset($_url['scheme']) ? ('https:' . $sm_cloud['fileLink']) : $sm_cloud['fileLink'];
1809 + $url = apply_filters('wp_stateless_bucket_link', $url);
1810 + } elseif (is_multisite() && empty($sm_cloud)) {
1811 + $_file = get_post_meta($post_id, '_wp_attached_file', true);
1812 + if ($_file) {
1813 + if ($this->get('sm.mode') == 'stateless') {
1814 + $default_dir = true;
1815 + $uploads = wp_get_upload_dir();
1816 + $default_dir = false;
1817 + $url = $uploads['baseurl'] . '/' . $_file;
1818 + } else {
1819 + $uploads = wp_get_upload_dir();
1820 + $default_dir = false;
1821 + $_file = apply_filters('wp_stateless_file_name', $_file, false);
1822 + $blog_id = get_current_blog_id();
1823 + $file_path_fix = $uploads['basedir'] . "/sites/$blog_id/$_file";
1824 +
1825 + if (file_exists($file_path_fix)) {
1826 + $url = $uploads['baseurl'] . "/sites/$blog_id/$_file";
1827 + }
1828 + }
1829 + }
1830 + } elseif (empty($sm_cloud) && $this->get('sm.mode') == 'stateless') {
1831 + $_file = get_post_meta($post_id, '_wp_attached_file', true);
1832 + if ($_file) {
1833 + $default_dir = true;
1834 + $uploads = wp_get_upload_dir();
1835 + $default_dir = false;
1836 +
1837 + $url = $uploads['baseurl'] . '/' . $_file;
1838 + }
1349 1839 }
1350 - return $url;
1840 +
1841 + return apply_filters('wp_stateless_attachment_url', $url, $post_id);
1351 1842 }
1352 1843
1353 1844 /**
1354 1845 * Filter for attachment_url_to_postid()
1355 - *
1846 + *
1356 1847 * @param int|false $post_id originally found post ID (or false if not found)
1357 1848 * @param string $url the URL to find the post ID for
1358 1849 * @return int|false found post ID from cloud storage URL
1359 1850 */
1360 - public function attachment_url_to_postid( $post_id, $url ) {
1851 + public function attachment_url_to_postid($post_id, $url) {
1361 1852 global $wpdb;
1362 1853
1363 - if ( ! $post_id ) {
1854 + if (!$post_id) {
1364 1855 $post_id = get_transient("stateless_url_to_postid_" . md5($url));
1365 1856
1366 - if(defined('WP_STATELESS_LEGACY_URL_TO_POSTID')){
1857 + if (defined('WP_STATELESS_LEGACY_URL_TO_POSTID')) {
1367 1858 // User can use this constant if they change the Bucket Folder (root_dir) after uploading image.
1368 1859 // This can be little slow at first run.
1369 - if(empty($post_id)){
1370 - $query = "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sm_cloud' AND meta_value LIKE '%s'";
1371 - $post_id = $wpdb->get_var( $wpdb->prepare( $query, '%' . $url . '%' ) );
1860 + if (empty($post_id)) {
1861 + if ( !$this->get('sm.use_postmeta') ) {
1862 + $query = 'SELECT post_id FROM ' . ud_stateless_db()->files . ' WHERE file_link = %s';
1863 + $post_id = $wpdb->get_var($wpdb->prepare($query, $url));
1864 + }
1865 +
1866 + if (empty($post_id)) {
1867 + $query = "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sm_cloud' AND meta_value LIKE '%s'";
1868 + $post_id = $wpdb->get_var($wpdb->prepare($query, '%' . $url . '%'));
1869 + }
1372 1870
1373 - if($post_id){
1871 + if ($post_id) {
1374 1872 set_transient("stateless_url_to_postid_" . md5($url), $post_id);
1375 1873 }
1376 1874 }
1377 1875 return $post_id;
@@ -1376,34 +1874,46 @@
1376 1874 }
1377 1875 return $post_id;
1378 1876 }
1379 1877
1380 - if(empty($post_id)){
1878 + if (empty($post_id)) {
1381 1879 $gs_base_url = $this->get_gs_host();
1382 - $gs_url = $this->get_gs_host() . '/' . $this->get( 'sm.root_dir' );
1880 + $root_dir = $this->get('sm.root_dir');
1881 + $path_elements = apply_filters('wp_stateless_unhandle_root_dir', $url);
1882 + $root_dir = apply_filters("wp_stateless_handle_root_dir", $root_dir, false, $path_elements);
1883 + $gs_url = $this->get_gs_host() . '/' . $root_dir;
1383 1884 $site_url = parse_url($gs_url);
1384 - $image_path = parse_url( $url );
1885 + $image_path = parse_url($url);
1385 1886
1386 1887 //force the protocols to match if needed
1387 - if( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
1388 - $url = str_replace( $image_path['scheme'], $site_url['scheme'], $url );
1888 + if (isset($image_path['scheme']) && ($image_path['scheme'] !== $site_url['scheme'])) {
1889 + $url = str_replace($image_path['scheme'], $site_url['scheme'], $url);
1389 1890 }
1390 1891
1391 - if( 0 === strpos( $url, $gs_url . '/' ) ) {
1392 - $url = substr( $url, strlen( $gs_url . '/' ) );
1892 + if (0 === strpos($url, $gs_url . '/')) {
1893 + $url = substr($url, strlen($gs_url . '/'));
1894 + } else if (0 === strpos($url, $gs_base_url . '/')) {
1895 + // In case user added Bucket Folder (root_dir) after uploading image.
1896 + $url = substr($url, strlen($gs_base_url . '/'));
1393 1897 }
1394 - else if( 0 === strpos( $url, $gs_base_url . '/' ) ) {
1395 - // In case user added Bucket Folder (root_dir) after uploading image.
1396 - $url = substr( $url, strlen( $gs_base_url . '/' ) );
1898 +
1899 + /**
1900 + * If `uploads_use_yearmonth_folders` is set - adding year and month to url
1901 + */
1902 + $organize_media = get_option('uploads_use_yearmonth_folders');
1903 + $path = '';
1904 + if ($organize_media == '1' && isset($path_elements['%date_year/date_month%'])) {
1905 + $path .= $path_elements['%date_year/date_month%'] . '/';
1397 1906 }
1907 + $url = $path . $url;
1398 1908
1399 1909 $sql = $wpdb->prepare(
1400 1910 "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
1401 1911 $url
1402 1912 );
1403 - $post_id = $wpdb->get_var( $sql );
1913 + $post_id = $wpdb->get_var($sql);
1404 1914
1405 - if($post_id){
1915 + if ($post_id) {
1406 1916 set_transient("stateless_url_to_postid_" . md5($url), $post_id);
1407 1917 }
1408 1918 }
1409 1919 }
@@ -1411,40 +1921,19 @@
1411 1921 return $post_id;
1412 1922 }
1413 1923
1414 1924 /**
1415 - * Upload the full size image first.
1416 - *
1417 - */
1418 - public function before_intermediate_image_sizes($sizes, $metadata = array()){
1419 - if(empty($metadata)){
1420 - return $sizes;
1421 - }
1422 -
1423 - try{
1424 - $attachment_id = attachment_url_to_postid($metadata['file']);
1425 - $this->add_media(null, $attachment_id, false, array('no_thumb' => true));
1426 - }
1427 - catch(Exception $e){
1428 -
1429 - }
1430 -
1431 - return $sizes;
1432 - }
1433 -
1434 - /**
1435 1925 * Change Upload BaseURL when CDN Used.
1436 1926 *
1437 1927 * @param $data
1438 1928 * @return mixed
1439 1929 */
1440 - public function upload_dir( $data ) {
1441 - $data[ 'basedir' ] = $this->get_gs_host();
1442 - $data[ 'baseurl' ] = $this->get_gs_host();
1443 - $data[ 'url' ] = $data[ 'baseurl' ] . $data[ 'subdir' ];
1930 + public function upload_dir($data) {
1931 + $data['basedir'] = $this->get_gs_host();
1932 + $data['baseurl'] = $this->get_gs_host();
1933 + $data['url'] = $data['baseurl'] . $data['subdir'];
1444 1934
1445 1935 return $data;
1446 -
1447 1936 }
1448 1937
1449 1938 /**
1450 1939 * Set Feature Flag constants by parsing composer.json
@@ -1453,42 +1942,39 @@
1453 1942 *
1454 1943 * @author potanin@UD
1455 1944 * @return array|mixed|null|object
1456 1945 */
1457 - public function parse_feature_flags( ) {
1946 + public function parse_feature_flags() {
1458 1947
1459 1948 try {
1460 1949
1461 - $_raw = file_get_contents( Utility::normalize_path( $this->root_path ) . 'composer.json' );
1950 + $_raw = file_get_contents(Utility::normalize_path($this->root_path) . 'composer.json');
1462 1951
1463 - $_parsed = json_decode( $_raw );
1952 + $_parsed = json_decode($_raw);
1464 1953
1465 1954 // @todo Catch poorly formatted JSON.
1466 - if( !is_object( $_parsed ) ) {
1955 + if (!is_object($_parsed)) {
1467 1956 // throw new Error( "unable to parse." );
1468 1957 }
1469 1958
1470 - foreach( (array) $_parsed->extra->featureFlags as $_feature ) {
1959 + foreach ((array) $_parsed->extra->featureFlags as $_feature) {
1471 1960
1472 - if( !defined( $_feature->constant ) ) {
1473 - define( $_feature->constant, $_feature->enabled );
1961 + if (!defined($_feature->constant)) {
1962 + define($_feature->constant, $_feature->enabled);
1474 1963
1475 - if( $_feature->enabled ) {
1476 - Utility::log( 'Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] enabled.' );
1964 + if ($_feature->enabled) {
1965 + Utility::log('Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] enabled.');
1477 1966 } else {
1478 - Utility::log( 'Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] disabled.' );
1967 + Utility::log('Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] disabled.');
1479 1968 }
1480 1969 }
1481 -
1482 1970 }
1483 -
1484 - } catch ( Exception $e ) {
1485 - Utility::log( 'Unable to parse [composer.json] feature flags. Error: [' . $e->getMessage() . ']' );
1971 + } catch (\Exception $e) {
1972 + Utility::log('Unable to parse [composer.json] feature flags. Error: [' . $e->getMessage() . ']');
1486 1973 // echo 'Caught exception: ', $e->getMessage(), "\n";
1487 1974 }
1488 1975
1489 - return isset( $_parsed ) ? $_parsed : null;
1490 -
1976 + return isset($_parsed) ? $_parsed : null;
1491 1977 }
1492 1978
1493 1979 /**
1494 1980 * Determine if Utility class contains missed function
@@ -1498,14 +1984,137 @@
1498 1984 * @param $name
1499 1985 * @param $arguments
1500 1986 * @return mixed|null
1501 1987 */
1502 - public function __call( $name, $arguments ) {
1503 - if( is_callable( array( "wpCloud\\StatelessMedia\\Utility", $name ) ) ) {
1504 - return call_user_func_array( array( "wpCloud\\StatelessMedia\\Utility", $name ), $arguments );
1988 + public function __call($name, $arguments) {
1989 + if (is_callable(array("wpCloud\\StatelessMedia\\Utility", $name))) {
1990 + return call_user_func_array(array("wpCloud\\StatelessMedia\\Utility", $name), $arguments);
1505 1991 } else {
1506 1992 return NULL;
1507 1993 }
1994 + }
1995 +
1996 + /**
1997 + * Get all thumbnail sizes
1998 + *
1999 + * @global $_wp_additional_image_sizes
2000 + * @uses get_intermediate_image_sizes()
2001 + *
2002 + * @param boolean [$unset_disabled = true]
2003 + * @return array
2004 + */
2005 + function get_image_sizes($unset_disabled = true) {
2006 + $wais = &$GLOBALS['_wp_additional_image_sizes'];
2007 +
2008 + $sizes = array();
2009 +
2010 + foreach (get_intermediate_image_sizes() as $_size) {
2011 + if (in_array($_size, array('thumbnail', 'medium', 'medium_large', 'large'))) {
2012 + $sizes[$_size] = array(
2013 + 'width' => get_option("{$_size}_size_w"),
2014 + 'height' => get_option("{$_size}_size_h"),
2015 + 'crop' => (bool) get_option("{$_size}_crop"),
2016 + );
2017 + } elseif (isset($wais[$_size])) {
2018 + $sizes[$_size] = array(
2019 + 'width' => $wais[$_size]['width'],
2020 + 'height' => $wais[$_size]['height'],
2021 + 'crop' => $wais[$_size]['crop'],
2022 + );
2023 + }
2024 +
2025 + // size registered, but has 0 width and height
2026 + if ($unset_disabled && ($sizes[$_size]['width'] == 0) && ($sizes[$_size]['height'] == 0))
2027 + unset($sizes[$_size]);
2028 + }
2029 +
2030 + return $sizes;
2031 + }
2032 +
2033 + /**
2034 + * Get the email for notifications
2035 + *
2036 + * @return string
2037 + */
2038 + public function get_notification_email() {
2039 + $type = $this->get( 'sm.status_email_type' );
2040 +
2041 + switch ($type) {
2042 + case 'true':
2043 + // Emails to Admin
2044 + return get_site_option('admin_email');
2045 + case 'custom':
2046 + // Emails to Custom Email
2047 + return $this->get( 'sm.status_email_address' );
2048 + }
2049 +
2050 + // Emails disabled
2051 + return '';
2052 + }
2053 +
2054 + /**
2055 + * Send admin email
2056 + *
2057 + * @param string $subject
2058 + * @param string $message
2059 + * @param string $email
2060 + */
2061 + public function send_admin_email($subject, $message, $email = '') {
2062 + $admin_email = empty($email) ? $this->get_notification_email() : $email;
2063 +
2064 + $admin_email = explode(',', $admin_email);
2065 + $admin_email = array_map( function($item) {
2066 + return strip_tags( trim($item) );
2067 + }, $admin_email);
2068 +
2069 + if ( empty($admin_email) || empty($subject) || empty($message) ) {
2070 + return;
2071 + }
2072 +
2073 + wp_mail( $admin_email, $subject, $message);
2074 + }
2075 +
2076 + /**
2077 + * Check if we are in specific mode
2078 + *
2079 + * @param string|array $mode
2080 + * @return bool
2081 + */
2082 + public function is_mode($mode) {
2083 + if ( !is_array($mode) ) {
2084 + $mode = [$mode];
2085 + }
2086 +
2087 + return in_array($this->get('sm.mode'), $mode);
2088 + }
2089 +
2090 + /**
2091 + * Get default cache control value
2092 + *
2093 + * @return string
2094 + */
2095 + public function get_default_cache_control() {
2096 + return Settings::DEFAULT_CACHE_CONTROL;
2097 + }
2098 +
2099 + /**
2100 + * Override REST API root for headless CMS
2101 + *
2102 + * @return string
2103 + */
2104 + public function get_rest_api_root($rest_api_root) {
2105 + $rest_api_root = sanitize_url( get_rest_url() );
2106 + $rest_api_root .= 'wp-stateless/v1/';
2107 +
2108 + if ( $this->get('sm.use_api_siteurl') == 'WP_SITEURL' ) {
2109 + $home = get_home_url();
2110 + $site = get_site_url();
2111 +
2112 + return str_replace( $home, $site, $rest_api_root );
2113 + }
2114 +
2115 +
2116 + return $rest_api_root;
1508 2117 }
1509 2118 }
1510 2119 }
1511 2120 }