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 +1246 -617 2.2.6trunk 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,96 +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
190 + /**
191 + * Add the currently processing nag
192 + */
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 + }
205 +
150 206 /* Initialize plugin only if Mode is not 'disabled'. */
151 - if ( $this->get( 'sm.mode' ) !== 'disabled' ) {
207 + if (($sm_mode !== 'disabled' && $sm_mode !== 'stateless') || ($sm_mode === 'stateless' && (wp_doing_ajax() || wp_doing_cron()))) {
152 208
153 209 /**
154 - * 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.
155 212 */
156 - $cacheControl = trim($this->get( 'sm.cache_control' ));
157 - if ( !empty($cacheControl) ) {
158 - 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);
159 217 }
160 218
219 + if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
220 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
221 + }
222 +
161 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 + /**
162 278 * Determine if we have issues with connection to Google Storage Bucket
163 279 * if SM is not disabled.
164 280 */
165 281 $is_connected = $this->is_connected_to_gs();
166 282
167 - if ( is_wp_error( $is_connected ) ) {
168 - $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);
169 285 }
170 286
171 - if ( $googleSDKVersionConflictError = get_transient( "wp_stateless_google_sdk_conflict" ) ) {
172 - $this->errors->add( $googleSDKVersionConflictError, 'warning' );
287 + if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
288 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
173 289 }
174 290
175 - // To prevent fatal errors for users who use PHP 5.5 or less.
176 - if( version_compare(PHP_VERSION, '5.5', '<') ) {
177 - $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>' ) );
178 - }
179 -
180 - /** Temporary fix to WP 4.4 srcset feature **/
181 - //add_filter( 'max_srcset_image_width', function(){return 1;} );
182 -
183 291 /**
184 292 * Carry on only if we do not have errors.
185 293 */
186 - 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);
187 299
188 - if( $this->get( 'sm.mode' ) === 'cdn' || $this->get( 'sm.mode' ) === 'stateless' ) {
189 - add_filter( 'wp_get_attachment_image_attributes', array( $this, 'wp_get_attachment_image_attributes' ), 20, 3 );
190 - add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 20, 2 );
191 - 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'));
192 304
193 - if ( $this->get( 'sm.body_rewrite' ) == 'true' || $this->get( 'sm.body_rewrite' ) == 'enable_editor' ) {
194 - add_filter( 'the_content', array( $this, 'the_content_filter' ), 99 );
195 - }
305 + /**
306 + * Init GS client
307 + */
308 + global $gs_client;
309 + if ($gs_client = $this->init_gs_client()) {
310 + StreamWrapper::register($gs_client);
311 + }
196 312
197 - if ( $this->get( 'sm.body_rewrite' ) == 'true' || $this->get( 'sm.body_rewrite' ) == 'enable_meta' ) {
198 - add_filter( 'get_post_metadata', array( $this, 'post_metadata_filter' ), 2, 4 );
199 - }
313 + /**
314 + * init client's filters
315 + */
316 + $this->_init_filters('client');
200 317
201 - 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);
202 340 }
203 341
204 - if ( $root_dir = $this->get( 'sm.root_dir' ) ) {
205 - if ( trim( $root_dir, '/ ' ) !== '' ) { // Remove any forward slash and empty space.
206 - add_filter( 'wp_stateless_file_name', array( $this, 'handle_root_dir' ) );
207 - }
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);
208 344 }
209 345
346 + add_filter('wp_stateless_bucket_link', array($this, 'wp_stateless_bucket_link'));
347 + break;
348 + case 'client':
210 349 /**
211 - * Rewrite Image URLS
350 + * Add custom actions to media rows
212 351 */
213 - add_filter( 'image_downsize', array( $this, 'image_downsize' ), 99, 3 );
214 - 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);
215 353
216 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 + /**
217 369 * Extends metadata by adding GS information.
218 370 */
219 - 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);
220 372
221 373 /**
222 374 * Add/Edit Media
223 375 *
@@ -223,59 +375,148 @@
223 375 *
224 376 * Once added or edited we can get into Attachment ID then get all image sizes and sync them with GS
225 377 * We can't use this. That's prevent removing this filter.
226 378 */
227 - add_filter( 'wp_update_attachment_metadata', array( 'wpCloud\StatelessMedia\Utility', 'add_media' ), 999, 2 );
228 -
379 + add_filter('wp_update_attachment_metadata', array('wpCloud\StatelessMedia\Utility', 'add_media'), 999, 2);
380 +
229 381 /**
230 - * Upload the full size image first.
231 - *
382 + * Delete original in the end of generating metadata
383 + * it does not work with PDF
232 384 */
233 - if(!defined('WP_STATELESS_MEDIA_DISABLE_FULL_IMAGE_FIRST') || WP_STATELESS_MEDIA_DISABLE_FULL_IMAGE_FIRST != true){
234 - add_filter( 'intermediate_image_sizes_advanced', array( $this, 'before_intermediate_image_sizes' ), 10, 2 );
235 - }
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);
236 390
237 391 /**
238 - * Add Media
239 - *
240 - * Once added we can get into Attachment ID then get all image sizes and sync them with GS
392 + * Rewrite Image URLS
241 393 */
242 - // 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);
243 396
244 - if ( $this->get( 'sm.delete_remote' ) == 'true' ) {
245 - /**
246 - * On physical file deletion we remove any from GS
247 - */
248 - add_filter('delete_attachment', array($this, 'remove_media'));
249 - }
397 + /**
398 + * Trigger module initialization and registration.
399 + */
400 + do_action('sm::module::init', $this->get('sm'));
250 401
251 - // Trigger module initialization and registration.
252 - do_action('sm::module::init', $this->get( 'sm' ));
253 - }
402 + break;
403 + case 'default':
404 + break;
405 + }
406 + }
254 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'));
255 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 + }
256 448 }
257 -
449 +
258 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 + /**
259 485 * Rebuild srcset from gs_link.
260 486 * Using calculations returned from WordPress wp_calculate_image_srcset()
261 - *
487 + *
488 + * @param $sources
489 + * @param $size_array
490 + * @param $image_src
491 + * @param $image_meta
492 + * @param $attachment_id
493 + * @return array
262 494 */
263 - 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 +
264 505 if (empty($image_meta['gs_link'])) {
265 506 $image_meta = wp_get_attachment_metadata($attachment_id);
266 507 }
267 508
268 - if(is_array($sources) && !empty( $image_meta['gs_link'] )){
509 + if (is_array($sources) && !empty($image_meta['gs_link'])) {
269 510 $gs_name = $image_meta['gs_name'];
270 511 // getting position of root_dir in gs_name.
271 512 $root_dir_pos = strpos($gs_name, $image_meta['file']);
272 - // removing rood_dir from gs_name so we can compare to replace url with gs_link.
273 - 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) {
274 515 $gs_name = substr($gs_name, $root_dir_pos);
275 516 }
276 517
277 - if ( !isset($gs_name) || empty($gs_name) ) {
518 + if (!isset($gs_name) || empty($gs_name)) {
278 519 return [];
279 520 }
280 521
281 522 foreach ($sources as $width => &$image) {
@@ -282,9 +523,9 @@
282 523
283 524 // If srcset includes original image src, replace it
284 525 if (substr_compare($image['url'], $gs_name, -strlen($gs_name)) === 0) {
285 526 $image['url'] = $image_meta['gs_link'];
286 - // Replace all sizes
527 + // Replace all sizes
287 528 } elseif (isset($image_meta['sizes']) && is_array($image_meta['sizes'])) {
288 529 $found = false;
289 530 foreach ($image_meta['sizes'] as $key => $meta) {
290 531 if (!isset($meta['gs_name']) || empty($meta['gs_name'])) {
@@ -292,9 +533,9 @@
292 533 }
293 534
294 535 $thumb_gs_name = $meta['gs_name'];
295 536 // removing rood_dir from gs_name
296 - if($root_dir_pos !== false){
537 + if ($root_dir_pos !== false) {
297 538 $thumb_gs_name = substr($thumb_gs_name, $root_dir_pos);
298 539 }
299 540
300 541 if (substr_compare($image['url'], $thumb_gs_name, -strlen($thumb_gs_name)) === 0) {
@@ -303,22 +544,27 @@
303 544 break;
304 545 }
305 546 }
306 547
307 - // if no size found and mode is stateless and nothing to show for srcset item - unset that item
308 - 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')) {
309 550 $image = null;
310 551 }
311 552 } else {
312 553 // if mode is stateless and nothing to show for srcset item - unset that item
313 - if ( $this->get( 'sm.mode' ) === 'stateless' ) {
554 + if ($sm_mode === 'ephemeral' || $sm_mode === 'stateless') {
314 555 $image = null;
315 556 }
316 557 }
317 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 + }
318 564 }
319 565
320 - return array_filter( $sources );
566 + return is_array($sources) ? array_filter($sources) : $sources;
321 567 }
322 568
323 569 /**
324 570 * Return gs host.
@@ -328,9 +574,9 @@
328 574 * @param array $sm
329 575 * @return mixed|void
330 576 */
331 577 public function get_gs_host($sm = array()) {
332 - $sm = $sm?$sm: $this->get( 'sm');
578 + $sm = $sm ? $sm : $this->get('sm');
333 579 $image_host = 'https://storage.googleapis.com/';
334 580 $image_host .= $sm['bucket'];
335 581
336 582 $custom_domain = $sm['custom_domain'];
@@ -340,17 +586,29 @@
340 586
341 587 // checking whether the provided domain is valid.
342 588 // if the custom domain is same as the bucket name
343 589 // or the custom domain is using https.
344 - 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'])) {
345 591 $image_host = $is_ssl === 0 ? 'https://' : 'http://'; // bucketname will be host
346 592 $image_host .= $custom_domain;
347 593 }
348 594
349 - 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);
350 596 }
351 597
352 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 + /**
353 611 * Filter for wp_stateless_bucket_link if custom domain is set.
354 612 * It's get attachment url and remove "storage.googleapis.com" from url.
355 613 * So that custom url can be used.
356 614 *
@@ -357,20 +615,19 @@
357 615 * @param $fileLink
358 616 * @return mixed|string
359 617 */
360 618 public function wp_stateless_bucket_link($fileLink) {
361 - $bucketname = $this->get( 'sm.bucket' );
362 - $custom_domain = $this->get( 'sm.custom_domain' );
619 + $bucketname = $this->get('sm.bucket');
620 + $custom_domain = $this->get('sm.custom_domain');
363 621 $is_ssl = strpos($custom_domain, 'https://') === 0;
364 622 $fileLink_is_ssl = strpos($fileLink, 'https://') === 0;
365 623 $custom_domain = str_replace(array('http://', 'https://'), '', $custom_domain);
366 624 $custom_domain = trim($custom_domain, '/');
367 -
368 - 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) {
369 627 $fileLink = ($is_ssl ? 'https://' : 'http://') . substr($fileLink, strpos($fileLink, $bucketname));
370 - }
371 - elseif( $custom_domain !== 'storage.googleapis.com' && $custom_domain == $bucketname && $fileLink_is_ssl !== $is_ssl){
372 - if($is_ssl)
628 + } elseif ($custom_domain !== 'storage.googleapis.com' && $custom_domain == $bucketname && $fileLink_is_ssl !== $is_ssl) {
629 + if ($is_ssl)
373 630 $fileLink = str_replace(array('http://', 'https://'), 'https://', $fileLink);
374 631 else
375 632 $fileLink = str_replace(array('http://', 'https://'), 'http://', $fileLink);
376 633 }
@@ -382,19 +639,31 @@
382 639 *
383 640 * @param string $path
384 641 * @return string
385 642 */
386 - public function get_settings_page_url( $path = '' ) {
387 - $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'));
388 645 return $url . $path;
389 646 }
390 647
391 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 + /**
392 661 * Get new blog settings once switched blog.
393 662 * @param $new_blog
394 663 * @param $prev_blog_id
395 664 */
396 - public function on_switch_blog( $new_blog, $prev_blog_id ) {
665 + public function on_switch_blog($new_blog, $prev_blog_id) {
397 666 $this->settings->refresh();
398 667 }
399 668
400 669 /**
@@ -406,37 +675,37 @@
406 675 */
407 676 public function get_settings($settings) {
408 677
409 678 $settings_list = array(
410 - 'mode',
411 - 'body_rewrite',
412 - 'body_rewrite_types',
413 - 'bucket',
414 - 'root_dir',
415 - 'key_json',
416 - 'cache_control',
417 - 'delete_remote',
418 - 'custom_domain',
419 - 'organize_media',
420 - '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'
421 690 );
422 691
423 692 foreach ($settings_list as $setting) {
424 693
425 694 /** If setting is already exist, just skip it */
426 - if( isset( $settings[ $setting ] ) ) {
695 + if (isset($settings[$setting])) {
427 696 continue;
428 697 }
429 698
430 - $value = $this->get( 'sm.' . $setting );
699 + $value = $this->get('sm.' . $setting);
431 700
432 701 /** Decode json to array */
433 - if( $value && is_string( $value ) && $setting === 'key_json' ) {
434 - $value = json_decode( $value, true );
702 + if ($value && is_string($value) && $setting === 'key_json') {
703 + $value = json_decode($value, true);
435 704 $setting = 'key';
436 705 }
437 706
438 - $settings[ $setting ] = $value;
707 + $settings[$setting] = $value;
439 708 }
440 709
441 710 return $settings;
442 711 }
@@ -442,8 +711,9 @@
442 711 }
443 712
444 713 /**
445 714 * Remove all settings.
715 + * @param bool $network
446 716 */
447 717 public function reset($network = false) {
448 718 $this->settings->reset($network);
449 719 }
@@ -453,44 +723,33 @@
453 723 * @param $post
454 724 * @param $detached
455 725 * @return mixed
456 726 */
457 - public function add_custom_row_actions( $actions, $post, $detached ) {
727 + public function add_custom_row_actions($actions, $post, $detached) {
458 728
459 - if ( !current_user_can( 'upload_files' ) ) return $actions;
729 + if (!current_user_can('upload_files')) return $actions;
460 730
461 - if ( $post && 'attachment' == $post->post_type && 'image/' == substr( $post->post_mime_type, 0, 6 ) ) {
462 - $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>';
463 739 }
464 740
465 - if ( $post && 'attachment' == $post->post_type && 'image/' != substr( $post->post_mime_type, 0, 6 ) ) {
466 - $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>';
467 743 }
468 744
469 745 return $actions;
470 -
471 746 }
472 747
473 748 /**
474 - * Register metaboxes
475 - */
476 - public function register_metaboxes() {
477 - add_meta_box(
478 - 'sm-attachment-metabox',
479 - __( 'Google Cloud Storage', ud_get_stateless_media()->domain ),
480 - array($this, 'attachment_meta_box_callback'),
481 - 'attachment',
482 - 'side',
483 - 'low'
484 - );
485 - }
486 -
487 - /**
488 749 * Define REST API.
489 750 *
490 - * // https://usabilitydynamics-sandbox-uds-io-stateless-testing.c.rabbit.ci/wp-json/wp-stateless/v1
491 - *
492 - * @author potanin@UD
751 + * @author korotkov@UD
493 752 */
494 753 public function api_init() {
495 754
496 755 $route_namespace = 'wp-stateless/v1';
@@ -495,126 +754,305 @@
495 754
496 755 $route_namespace = 'wp-stateless/v1';
497 756 $api_namespace = 'wpCloud\StatelessMedia\API';
498 757
499 - register_rest_route( $route_namespace, '/status', array(
500 - 'methods' => 'GET',
501 - 'callback' => array( $api_namespace, 'status' ),
502 - ) );
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 + ));
503 763
504 - register_rest_route( $route_namespace, '/jobs', array(
505 - 'methods' => 'GET',
506 - 'callback' => array( $api_namespace, 'jobs' ),
507 - ) );
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 + ));
508 769
509 - /**
510 - * Return stateless settings.
511 - *
512 - * Request parameter: none
513 - *
514 - * Response:
515 - * ok: Whether API is up or not
516 - * message: Describe what is done or error message on error.
517 - * settings: array of stateless settings
518 - *
519 - */
520 - 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 + ));
521 775
522 - /**
523 - * Essentially for scrolling through media library to build our index.
524 - *
525 - * Request parameter: none
526 - *
527 - * Response:
528 - * ok: Whether API is up or not
529 - * message: Describe what is done or error message on error.
530 - * settings: array of media files
531 - *
532 - */
533 - 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 + ));
534 781
535 - /**
536 - * Get detailed information of media file
537 - *
538 - * Request parameter: none
539 - *
540 - * Response:
541 - * ok: Whether API is up or not
542 - * message: Describe what is done or error message on error.
543 - * settings: media file array
544 - *
545 - */
546 - 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 + ));
547 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;
548 835 }
549 836
550 837 /**
551 - * @param $post
838 + * Metabox for media edit page
839 + * @param $meta_boxes
840 + * @return array
552 841 */
553 - public function attachment_meta_box_callback( $post ) {
554 - 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 + }
555 853
556 - $sm_cloud = get_post_meta( $post->ID, 'sm_cloud', 1 );
854 + return $this->_prepare_data_for_metabox($meta_boxes, $post_id);
855 + }
557 856
558 - 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');
559 867
560 - <?php if( !empty( $sm_cloud[ 'cacheControl' ] ) ) { ?>
561 - <div class="misc-pub-cache-control hidden">
562 - <?php _e( 'Cache Control:', ud_get_stateless_media()->domain ); ?> <strong><span><?php echo $sm_cloud[ 'cacheControl' ]; ?></span> </strong>
563 - </div>
564 - <?php } ?>
868 + if (empty($post)) {
869 + return $meta_boxes;
870 + }
565 871
566 - <div class="misc-pub-gs-file-link" style="margin-bottom: 15px;">
567 - <label>
568 - <?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>
569 - <input type="text" class="widefat urlfield" readonly="readonly" value="<?php echo esc_attr($sm_cloud[ 'fileLink' ]); ?>" />
570 - </label>
571 - </div>
872 + $sizes = $this->get_image_sizes();
572 873
573 - <?php
874 + $fields = array();
574 875
575 - if ( !empty( $sm_cloud[ 'bucket' ] ) ) {
576 - ?>
577 - <div class="misc-pub-gs-bucket" style="margin-bottom: 15px;">
578 - <label>
579 - <?php _e( 'Storage Bucket:', ud_get_stateless_media()->domain ); ?>
580 - <input type="text" class="widefat urlfield" readonly="readonly" value="gs://<?php echo esc_attr($sm_cloud[ 'bucket' ]); ?>" />
581 - </label>
582 - </div>
583 - <?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 + }
584 917 }
585 918
586 - if ( current_user_can( 'upload_files' ) ) {
587 - if ( $post && 'attachment' == $post->post_type && 'image/' == substr( $post->post_mime_type, 0, 6 ) ) {
588 - ?>
589 - <a href="javascript:;" data-type="image" data-id="<?php echo $post->ID; ?>"
590 - class="button-secondary sm_inline_sync"><?php _e('Regenerate and Sync with GCS', ud_get_stateless_media()->domain); ?></a>
591 - <?php
592 - }
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 + }
593 928
594 - if ( $post && 'attachment' == $post->post_type && 'image/' != substr( $post->post_mime_type, 0, 6 ) ) {
595 - ?>
596 - <a href="javascript:;" data-type="other" data-id="<?php echo $post->ID; ?>"
597 - class="button-secondary sm_inline_sync"><?php _e('Sync with GCS', ud_get_stateless_media()->domain); ?></a>
598 - <?php
599 - }
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 + );
600 938 }
601 939 }
602 940
603 - 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;
604 967 }
605 968
606 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 + /**
607 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
608 1005 * @return string
609 1006 */
610 - public function handle_root_dir( $current_path ) {
611 - $root_dir = $this->get( 'sm.root_dir' );
612 - $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);
613 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 +
1025 + $upload_dir = wp_upload_dir();
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);
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 +
614 1052 // skip adding root dir if it's already added.
615 - if ( !empty( $root_dir ) && strpos($current_path, $root_dir) !== 0 ) {
616 - return $root_dir . '/' . $current_path;
1053 + if (!empty($root_dir) && !preg_match($root_dir_regex, $current_path)) {
1054 + return $root_dir . '/' . trim($current_path, '/ ');
617 1055 }
618 1056
619 1057 return $current_path;
620 1058 }
@@ -622,20 +1060,25 @@
622 1060 /**
623 1061 * @param $content
624 1062 * @return mixed
625 1063 */
626 - public function the_content_filter( $content ) {
1064 + public function the_content_filter($content) {
627 1065
628 - if ( $upload_data = wp_upload_dir() ) {
1066 + if ($upload_data = wp_upload_dir()) {
629 1067
630 - if ( !empty( $upload_data['baseurl'] ) && !empty( $content ) ) {
631 - $baseurl = preg_replace('/https?:\/\//','',$upload_data['baseurl']);
632 - $root_dir = trim( $this->get( 'sm.root_dir' ), '/ ' ); // Remove any forward slash and empty space.
633 - $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;
634 1074 $image_host = $this->get_gs_host();
635 1075 $file_ext = $this->replaceable_file_types();
636 - $content = preg_replace( '/(href|src)=(\'|")(https?:\/\/'.str_replace('/', '\/', $baseurl).')\/(.+?)('.$file_ext.')(\'|")/i',
637 - '$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 + );
638 1081 }
639 1082 }
640 1083
641 1084 return $content;
@@ -642,11 +1085,11 @@
642 1085 }
643 1086
644 1087 /**
645 1088 * Return file types supported by File URL Replacement.
646 - *
1089 + * @return string
647 1090 */
648 - public function replaceable_file_types(){
1091 + public function replaceable_file_types() {
649 1092 $types = $this->get('sm.body_rewrite_types');
650 1093
651 1094 // Removing extra space.
652 1095 $types = trim($types);
@@ -657,30 +1100,30 @@
657 1100 }
658 1101
659 1102 /**
660 1103 * Copied from https://developer.wordpress.org/reference/functions/get_metadata/
661 - *
1104 + *
662 1105 * @param $value null unless other filter hooked in this function.
663 1106 * @param $object_id post id
664 - * @param $meta_key
1107 + * @param $meta_key
665 1108 * @param $single
666 1109 * @return mixed
667 1110 */
668 - public function post_metadata_filter($value, $object_id, $meta_key, $single){
669 - if(empty($value)){
1111 + public function post_metadata_filter($value, $object_id, $meta_key, $single) {
1112 + if (empty($value)) {
670 1113 $meta_type = 'post';
671 1114 $transient_key = "stateless_{$meta_type}_meta";
672 -
1115 +
673 1116 $meta_cache = wp_cache_get($object_id, $transient_key);
674 - if(empty($meta_cache)){
1117 + if (empty($meta_cache)) {
675 1118 $meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
676 1119
677 - if ( !$meta_cache ) {
678 - $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));
679 1122 $meta_cache = $meta_cache[$object_id];
680 1123 }
681 -
682 - foreach($meta_cache as $key => $meta){
1124 +
1125 + foreach ($meta_cache as $key => $meta) {
683 1126 $meta_cache[$key] = array_map('maybe_unserialize', $meta_cache[$key]);
684 1127 }
685 1128
686 1129 $meta_cache = $this->convert_to_gs_link($meta_cache);
@@ -685,24 +1128,23 @@
685 1128
686 1129 $meta_cache = $this->convert_to_gs_link($meta_cache);
687 1130 wp_cache_set($object_id, $meta_cache, $transient_key);
688 1131 }
689 -
690 - if ( ! $meta_key ) {
1132 +
1133 + if (!$meta_key) {
691 1134 return $meta_cache;
692 1135 }
693 -
694 - if ( isset($meta_cache[$meta_key]) ) {
1136 +
1137 + if (isset($meta_cache[$meta_key])) {
695 1138 return $meta_cache[$meta_key];
696 1139 }
697 -
698 - // 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.
699 1142 // $value most of the time is null.
700 1143 return $value;
701 1144 }
702 1145
703 1146 return $this->convert_to_gs_link($value);
704 -
705 1147 }
706 1148
707 1149 /**
708 1150 * Replace all image link with gs link and return only if meta modified.
@@ -707,24 +1149,26 @@
707 1149 /**
708 1150 * Replace all image link with gs link and return only if meta modified.
709 1151 *
710 1152 * @param $meta
1153 + * @param $return
711 1154 * @return mixed or null when not changed.
712 1155 */
713 - public function convert_to_gs_link($meta){
1156 + public function convert_to_gs_link($meta, $return = false) {
714 1157 $updated = $meta;
715 - if ( $meta && $upload_data = wp_upload_dir() ) {
716 - if ( !empty( $upload_data['baseurl'] ) && !empty( $meta ) ) {
717 - $baseurl = preg_replace('/https?:\/\//','',$upload_data['baseurl']);
718 - $root_dir = trim( $this->get( 'sm.root_dir' ), '/ ' ); // Remove any forward slash and empty space.
719 - $root_dir = !empty( $root_dir ) ? $root_dir . '/': false;
720 - $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 : '');
721 1165 $file_ext = $this->replaceable_file_types();
722 - $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);
723 1167 }
724 1168 }
725 1169
726 - if($updated == $meta){
1170 + if ($updated == $meta && !$return) {
727 1171 return null; // Not changed.
728 1172 }
729 1173 return $updated;
730 1174 }
@@ -732,69 +1176,54 @@
732 1176 /**
733 1177 * Replace all image link with gs link
734 1178 *
735 1179 * @param $meta
736 - * @return mixed
1180 + * @param $image_host
1181 + * @param $url
1182 + * @param $file_ext
1183 + * @return array|null|string|string[]
737 1184 */
738 - public function _convert_to_gs_link($meta, $image_host, $baseurl, $file_ext){
739 - if(is_array($meta)){
1185 + public function _convert_to_gs_link($meta, $image_host, $url, $file_ext) {
1186 + if (is_array($meta)) {
740 1187 foreach ($meta as $key => $value) {
741 - $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);
742 1189 }
743 1190 return $meta;
744 - } elseif (is_object($meta) && $meta instanceof \stdClass ) {
1191 + } elseif (is_object($meta) && $meta instanceof \stdClass) {
745 1192 foreach (get_object_vars($meta) as $key => $value) {
746 - $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);
747 1194 }
748 1195 return $meta;
749 - } elseif(is_string($meta)){
750 - 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);
751 1198 }
752 1199
753 1200 return $meta;
754 1201 }
755 1202
756 -
757 1203 /**
758 - * @param $links
759 - * @param $file
760 - * @return mixed
761 - */
762 - public function plugin_action_links( $links, $file ) {
763 -
764 - if ($file == plugin_basename( dirname( __DIR__ ) . '/wp-stateless-media.php' ) ) {
765 - $settings_link = '<a href="'. '' .'">'.__( 'Settings' , 'ssd').'</a>';
766 - array_unshift( $links, $settings_link );
767 - }
768 -
769 - if ($file == plugin_basename( dirname( __DIR__ ) . '/wp-stateless.php' ) ) {
770 - $settings_link = '<a href="'. '' .'">'.__( 'Settings' , 'ssd').'</a>';
771 - array_unshift( $links, $settings_link );
772 - }
773 -
774 - return $links;
775 - }
776 -
777 - /**
778 1204 * Determines if plugin is loaded via mu-plugins
779 1205 * or Network Enabled.
780 1206 *
1207 + * @param bool $is_multisite
1208 + * @return bool
781 1209 * @author peshkov@UD
782 1210 */
783 - public function is_network_detected() {
1211 + public function is_network_detected($is_multisite = false) {
784 1212 /* Plugin is loaded via mu-plugins. */
785 1213
786 - 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) {
787 1215 return true;
788 1216 }
789 1217
790 - if( is_multisite() ) {
1218 + if (is_multisite()) {
1219 + if ($is_multisite) return true;
791 1220 /* Looks through network enabled plugins to see if our one is there. */
792 1221 foreach (wp_get_active_network_plugins() as $path) {
793 1222 // Trying again using readlink in case it's a symlink file.
794 1223 // boot_file is already solved.
795 1224 // wp_normalize_path is helpfull in windows.
796 - 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))) {
797 1226 return true;
798 1227 }
799 1228 }
800 1229 }
@@ -806,58 +1235,65 @@
806 1235 * Register scripts and styles
807 1236 */
808 1237 public function admin_init() {
809 1238 $this->show_notice_stateless_cache_busting();
810 - 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);
811 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 +
812 1246 /* Attachment or upload page */
813 - 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 + ]);
814 1251
815 - /* Setup wizard styles and scripts. */
816 - wp_register_style( 'wp-stateless-bootstrap', $this->path( 'static/styles/bootstrap.min.css', 'url' ), array(), '3.3.7' );
817 - wp_register_style( 'bootstrap-grid-v4', $this->path( 'static/styles/bootstrap-grid.min.css', 'url' ), array(), '3.3.7' );
818 - 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);
819 1255
820 - wp_register_script( 'async.min', ud_get_stateless_media()->path( 'static/scripts/async.js', 'url' ), array(), ud_get_stateless_media()->version );
821 - wp_register_script( 'jquery.history', ud_get_stateless_media()->path( 'static/scripts/jquery.history.js', 'url' ), array( 'jquery' ), ud_get_stateless_media()->version, true );
822 - 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 );
823 - 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 );
824 - 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 );
825 - 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 );
826 - 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);
827 1257
828 - 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());
829 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);
830 1265
831 - /* Stateless settings page */
832 - wp_register_script( 'wp-stateless-settings', ud_get_stateless_media()->path( 'static/scripts/wp-stateless-settings.js', 'url' ), array(), ud_get_stateless_media()->version );
833 - wp_localize_script( 'wp-stateless-settings', 'stateless_l10n', $this->get_l10n_data() );
834 -
835 - 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);
836 1268
837 - // Sync tab
838 - if ( wp_script_is( 'jquery-ui-widget', 'registered' ) ){
839 - 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' );
840 - }
841 - else{
842 - 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' );
843 - }
844 - wp_register_script( 'wp-stateless-angular', ud_get_stateless_media()->path( 'static/scripts/angular.min.js', 'url' ), array(), '1.5.0', true );
845 - 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 );
846 -
847 - wp_localize_script( 'wp-stateless', 'stateless_l10n', $this->get_l10n_data() );
1269 + wp_localize_script('wp-stateless', 'stateless_l10n', $this->get_l10n_data());
848 1270 wp_localize_script('wp-stateless', 'wp_stateless_configs', array(
849 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),
850 1278 ));
851 -
1279 +
852 1280 $settings = ud_get_stateless_media()->get('sm');
853 - 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) {
854 1285 $settings['key_json'] = "Currently configured via a constant.";
855 1286 }
856 1287 wp_localize_script('wp-stateless', 'wp_stateless_settings', $settings);
857 - wp_localize_script('wp-stateless', 'wp_stateless_compatibility', Module::get_modules());
858 - 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' );
859 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 + ));
860 1296 }
861 1297
862 1298 /**
863 1299 * Get_l10n_data
@@ -864,10 +1300,10 @@
864 1300 *
865 1301 * @param string $value
866 1302 * @return mixed
867 1303 */
868 - public function get_l10n_data($value=''){
869 - 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');
870 1306 return $l10n;
871 1307 }
872 1308
873 1309 /**
@@ -874,24 +1310,20 @@
874 1310 * Admin Scripts
875 1311 *
876 1312 * @param $hook
877 1313 */
878 - public function admin_enqueue_scripts( $hook ) {
1314 + public function admin_enqueue_scripts($hook) {
879 1315
880 - switch( $hook ) {
1316 + switch ($hook) {
881 1317
882 1318 case 'options-media.php':
883 - //wp_enqueue_script( 'wp-api' );
1319 + wp_enqueue_style('wp-stateless');
1320 + break;
884 1321
885 - wp_enqueue_style( 'wp-stateless');
886 - wp_enqueue_script( 'wp-stateless-setup' );
887 - break;
888 -
889 1322 case 'upload.php':
1323 + wp_enqueue_style('wp-stateless');
1324 + wp_enqueue_script('wp-stateless-uploads-js');
890 1325
891 - wp_enqueue_style( 'wp-stateless');
892 - wp_enqueue_script( 'wp-stateless-uploads-js' );
893 -
894 1326 break;
895 1327
896 1328 case 'post.php':
897 1329
@@ -896,57 +1328,60 @@
896 1328 case 'post.php':
897 1329
898 1330 global $post;
899 1331
900 - if ( $post->post_type == 'attachment' ) {
901 - wp_enqueue_style( 'wp-stateless');
902 - 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');
903 1335 }
904 1336
905 1337 break;
906 1338
907 - case 'media_page_stateless-setup':
1339 + // #152
1340 + // case 'media_page_stateless-setup':
908 1341 case 'settings_page_stateless-setup':
909 - wp_enqueue_style( 'wp-stateless');
910 - wp_enqueue_style( 'wp-stateless-bootstrap' );
911 - wp_enqueue_style( 'wp-stateless-setup-wizard' );
912 -
913 - wp_enqueue_script( 'async.min' );
914 - wp_enqueue_script( 'jquery.history' );
915 - wp_enqueue_script( 'wp-stateless-validation' );
916 - wp_enqueue_script( 'wp-stateless-loading' );
917 - wp_enqueue_script( 'wp-stateless-comboBox' );
918 - wp_enqueue_script( 'wp-stateless-setup' );
919 - wp_enqueue_script( 'wp-stateless-setup-wizard-js' );
1342 + wp_enqueue_style('wp-stateless');
1343 + // #152
1344 + // wp_enqueue_style('wp-stateless-setup-wizard');
920 1345 break;
921 1346 case 'media_page_stateless-settings':
922 1347 case 'settings_page_stateless-settings':
923 - wp_enqueue_style( 'wp-stateless');
924 - wp_enqueue_script( 'wp-stateless-settings' );
925 - wp_enqueue_style( 'bootstrap-grid-v4' );
926 - wp_enqueue_style( 'wp-stateless-settings' );
927 -
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 +
928 1357 // Sync tab
929 - wp_enqueue_script( 'jquery-ui-progressbar' );
930 - wp_enqueue_script( 'wp-stateless-angular' );
931 - wp_enqueue_script( 'wp-stateless' );
932 - wp_enqueue_style( 'jquery-ui-regenthumbs' );
1358 + wp_enqueue_script('wp-stateless');
933 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 +
934 1368 $data = array(
935 - 'key' => 'stateless-cache-busting',
936 - 'class' => 'notice',
937 - 'title' => sprintf( __( "Stateless mode enables and requires the Cache-Busting option.", ud_get_stateless_media()->domain ) ),
938 - 'message' => sprintf( __("WordPress looks at local files to prevent files with the same filenames.
939 - 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.
940 - Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain),"https://github.com/wpCloud/wp-stateless/wiki/Constants#wp_stateless_media_cache_busting", "WP_STATELESS_MEDIA_CACHE_BUSTING" ),
941 - );
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 + );
942 1376 echo "<script id='template-stateless-cache-busting' type='text/html'>";
943 - 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');
944 1378 echo "</script>";
1379 +
945 1380 break;
946 - default: break;
1381 + default:
1382 + break;
947 1383 }
948 -
949 1384 }
950 1385
951 1386 /**
952 1387 * Add Attributes to media HTML
@@ -956,20 +1391,19 @@
956 1391 * @param $attachment
957 1392 * @param $size
958 1393 * @return mixed
959 1394 */
960 - public function wp_get_attachment_image_attributes( $attr, $attachment, $size = null ) {
961 -
962 - $sm_cloud = get_post_meta( $attachment->ID, 'sm_cloud', true );
963 - if( is_array( $sm_cloud ) && !empty( $sm_cloud[ 'name' ] ) ) {
964 - $attr[ 'class' ] = $attr[ 'class' ] . ' wp-stateless-item';
965 - $attr[ 'data-image-size' ] = is_array( $size ) ? implode( 'x', $size ) : $size;
966 - $attr[ 'data-stateless-media-bucket' ] = isset( $sm_cloud[ 'bucket' ] ) ? $sm_cloud[ 'bucket' ] : false;
967 - $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'];
968 1403 }
969 1404
970 1405 return $attr;
971 -
972 1406 }
973 1407
974 1408 /**
975 1409 * Adds filter link to Media Library table.
@@ -976,10 +1410,10 @@
976 1410 *
977 1411 * @param $views
978 1412 * @return mixed
979 1413 */
980 - public function views_upload( $views ) {
981 - $views['stateless'] = '<a href="#">' . __( 'Stateless Media' ) . '</a>';
1414 + public function views_upload($views) {
1415 + $views['stateless'] = '<a href="#">' . __('Stateless Media') . '</a>';
982 1416 return $views;
983 1417 }
984 1418
985 1419 /**
@@ -989,11 +1423,11 @@
989 1423 * @param integer $id
990 1424 * @param string $size
991 1425 * @return mixed $false
992 1426 */
993 - public function image_downsize( $false = false, $id, $size ) {
1427 + public function image_downsize($false, $id, $size) {
994 1428
995 - 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') {
996 1430 return $false;
997 1431 }
998 1432
999 1433 /**
@@ -998,9 +1432,9 @@
998 1432
999 1433 /**
1000 1434 * Check if enabled
1001 1435 */
1002 - if ( $this->get( 'sm.mode' ) !== 'cdn' && $this->get( 'sm.mode' ) !== 'stateless' ) {
1436 + if (!in_array($this->get('sm.mode'), array('cdn', 'stateless', 'ephemeral'))) {
1003 1437 return $false;
1004 1438 }
1005 1439
1006 1440 /** Start determine remote file */
@@ -1009,19 +1443,17 @@
1009 1443 $width = $height = 0;
1010 1444 $is_intermediate = false;
1011 1445
1012 1446 //** try for a new style intermediate size */
1013 - if ( $intermediate = image_get_intermediate_size( $id, $size ) ) {
1014 - if(!empty( $intermediate['gs_link'] )){
1447 + if ($intermediate = image_get_intermediate_size($id, $size)) {
1448 + if (!empty($intermediate['gs_link'])) {
1015 1449 $img_url = $intermediate['gs_link'];
1016 - }
1017 - else if(!empty( $intermediate['url'] )){
1450 + } else if (!empty($intermediate['url'])) {
1018 1451 $img_url = $intermediate['url'];
1019 - }
1020 - else{
1452 + } else {
1021 1453 $img_url = dirname($img_url) . $intermediate['file'];
1022 1454 }
1023 -
1455 +
1024 1456 $width = $intermediate['width'];
1025 1457 $height = $intermediate['height'];
1026 1458 $is_intermediate = true;
1027 1459 }
@@ -1030,18 +1462,18 @@
1030 1462 * maybe try to get images info from sm_cloud
1031 1463 * this case may happen when no local files
1032 1464 * @author korotkov@ud
1033 1465 */
1034 - if ( !$width && !$height ) {
1035 - $sm_cloud = get_post_meta( $id, 'sm_cloud', true );
1036 - 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])) {
1037 1469 global $_wp_additional_image_sizes;
1038 1470
1039 - $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;
1040 1472
1041 - if ( !empty( $_wp_additional_image_sizes[ $size ] ) ) {
1042 - $width = !empty( $_wp_additional_image_sizes[ $size ]['width'] ) ? $_wp_additional_image_sizes[ $size ]['width'] : $width;
1043 - $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;
1044 1476 }
1045 1477
1046 1478 $is_intermediate = true;
1047 1479 }
@@ -1046,9 +1478,9 @@
1046 1478 $is_intermediate = true;
1047 1479 }
1048 1480 }
1049 1481
1050 - if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
1482 + if (!$width && !$height && isset($meta['width'], $meta['height'])) {
1051 1483
1052 1484 //** any other type: use the real image */
1053 1485 $width = $meta['width'];
1054 1486 $height = $meta['height'];
@@ -1054,14 +1486,14 @@
1054 1486 $height = $meta['height'];
1055 1487 }
1056 1488
1057 1489
1058 - if ( $img_url) {
1490 + if ($img_url) {
1059 1491
1060 1492 //** we have the actual image size, but might need to further constrain it if content_width is narrower */
1061 - list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
1493 + list($width, $height) = image_constrain_size_for_editor($width, $height, $size);
1062 1494 $img_url = apply_filters('wp_stateless_bucket_link', $img_url);
1063 - return array( $img_url, $width, $height, $is_intermediate );
1495 + return array($img_url, $width, $height, $is_intermediate);
1064 1496 }
1065 1497
1066 1498
1067 1499 /**
@@ -1067,9 +1499,8 @@
1067 1499 /**
1068 1500 * All other cases work as usually
1069 1501 */
1070 1502 return $false;
1071 -
1072 1503 }
1073 1504
1074 1505 /**
1075 1506 * Extends metadata by adding GS information.
@@ -1078,34 +1509,100 @@
1078 1509 * @param $metadata
1079 1510 * @param $attachment_id
1080 1511 * @return array|mixed
1081 1512 */
1082 - 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;
1083 1516 /* Determine if the media file has GS data at all. */
1084 - $sm_cloud = get_post_meta( $attachment_id, 'sm_cloud', true );
1517 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment_id, true);
1085 1518 // If metadata not passed the get metadata from post meta.
1086 - if(empty($metadata)){
1087 - $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);
1088 1521 }
1089 1522
1090 - if( is_array( $metadata ) && is_array( $sm_cloud ) && !empty( $sm_cloud[ 'fileLink' ] ) ) {
1091 - $metadata[ 'gs_link' ] = apply_filters('wp_stateless_bucket_link', $sm_cloud[ 'fileLink' ]);
1092 - $metadata[ 'gs_name' ] = isset( $sm_cloud[ 'name' ] ) ? $sm_cloud[ 'name' ] : false;
1093 - $metadata[ 'gs_bucket' ] = isset( $sm_cloud[ 'bucket' ] ) ? $sm_cloud[ 'bucket' ] : false;
1094 - if( !empty( $metadata[ 'sizes' ] ) && is_array( $metadata[ 'sizes' ] ) ) {
1095 - foreach( $metadata[ 'sizes' ] as $k => $v ) {
1096 - if( !empty( $sm_cloud[ 'sizes' ][ $k ][ 'name' ] ) ) {
1097 - $metadata['sizes'][$k]['gs_name'] = $sm_cloud[ 'sizes' ][ $k ][ 'name' ];
1098 - $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']);
1099 1536 }
1100 1537 }
1101 1538 }
1102 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;
1103 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 +
1104 1569 return $metadata;
1105 1570 }
1106 1571
1107 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 + /**
1108 1605 * Returns client object
1109 1606 * or WP_Error on failure.
1110 1607 *
1111 1608 * @author peshkov@UD
@@ -1112,24 +1609,23 @@
1112 1609 * @return object $this->client. \wpCloud\StatelessMedia\GS_Client or \WP_Error
1113 1610 */
1114 1611 public function get_client() {
1115 1612
1116 - if( null === $this->client ) {
1613 + if (null === $this->client) {
1117 1614
1118 - $key_json = get_site_option( 'sm_key_json' );
1119 - if ( empty($key_json) ) {
1120 - $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');
1121 1618 }
1122 1619
1123 1620 /* Try to initialize GS Client */
1124 - $this->client = GS_Client::get_instance( array(
1125 - 'bucket' => $this->get( 'sm.bucket' ),
1621 + $this->client = GS_Client::get_instance(array(
1622 + 'bucket' => $this->get('sm.bucket'),
1126 1623 'key_json' => $key_json
1127 - ) );
1624 + ));
1128 1625 }
1129 1626
1130 1627 return $this->client;
1131 -
1132 1628 }
1133 1629
1134 1630 /**
1135 1631 * Determines if we can connect to Google Storage Bucket.
@@ -1136,47 +1632,46 @@
1136 1632 *
1137 1633 * @author peshkov@UD
1138 1634 */
1139 1635 public function is_connected_to_gs() {
1636 + $trnst = get_transient('sm::is_connected_to_gs');
1140 1637
1141 - $trnst = get_transient( 'sm::is_connected_to_gs' );
1142 -
1143 - 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')))) {
1144 1639 $trnst = array(
1145 1640 'success' => 'true',
1146 1641 'error' => '',
1147 - 'hash' => md5( serialize( $this->get( 'sm' ) ) ),
1642 + 'hash' => md5(serialize($this->get('sm'))),
1148 1643 );
1149 1644 $client = $this->get_client();
1150 1645
1151 - if ( is_wp_error( $client ) ) {
1152 - $trnst[ 'success' ] = 'false';
1153 - $trnst[ 'error' ] = $client->get_error_message();
1646 + if (is_wp_error($client)) {
1647 + $trnst['success'] = 'false';
1648 + $trnst['error'] = $client->get_error_message();
1154 1649 } else {
1155 1650 $connected = $client->is_connected();
1156 - if( $connected !== true ) {
1157 - $trnst[ 'success' ] = 'false';
1158 - $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')));
1159 1654
1160 - if( is_callable(array($connected, 'getHandlerContext')) && $handlerContext = $connected->getHandlerContext() ){
1161 - if(!empty($handlerContext['error'])){
1655 + if (is_callable(array($connected, 'getHandlerContext')) && $handlerContext = $connected->getHandlerContext()) {
1656 + if (!empty($handlerContext['error'])) {
1162 1657 $handlerContext['error'];
1163 - $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']);
1164 1659 }
1165 1660 }
1166 1661
1167 - if( is_callable(array($connected, 'getErrors')) && $error = $connected->getErrors() ){
1662 + if (is_callable(array($connected, 'getErrors')) && $error = $connected->getErrors()) {
1168 1663 $error = reset($error);
1169 - if($error['reason'] == 'accessNotConfigured')
1170 - $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']);
1171 1666 }
1172 1667 }
1173 1668 }
1174 - 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);
1175 1670 }
1176 1671
1177 - if( isset( $trnst[ 'success' ] ) && $trnst[ 'success' ] == 'false' ) {
1178 - 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.'));
1179 1674 }
1180 1675
1181 1676 return true;
1182 1677 }
@@ -1185,9 +1680,9 @@
1185 1680 * Flush all plugin transients
1186 1681 *
1187 1682 */
1188 1683 public function flush_transients() {
1189 - delete_transient( 'sm::is_connected_to_gs' );
1684 + delete_transient('sm::is_connected_to_gs');
1190 1685 }
1191 1686
1192 1687 /**
1193 1688 * Plugin Activation
@@ -1193,9 +1688,9 @@
1193 1688 * Plugin Activation
1194 1689 *
1195 1690 */
1196 1691 public function activate() {
1197 - add_action( 'activated_plugin', array($this, 'redirect_to_splash'), 99 );
1692 + add_action('activated_plugin', array($this, 'redirect_to_splash'), 99);
1198 1693 $this->run_upgrade_process();
1199 1694 }
1200 1695
1201 1696 /**
@@ -1204,10 +1699,9 @@
1204 1699 * Works on even manual plugin update.
1205 1700 *
1206 1701 * @author alim@UD
1207 1702 */
1208 - public function run_install_process()
1209 - {
1703 + public function run_install_process() {
1210 1704 // calling the upgrade function because it's same as this point for fresh install or updates.
1211 1705 $this->run_upgrade_process();
1212 1706 }
1213 1707
@@ -1217,45 +1711,27 @@
1217 1711 * Works on even manual plugin update.
1218 1712 *
1219 1713 * @author alim@UD
1220 1714 */
1221 - public function run_upgrade_process()
1222 - {
1715 + public function run_upgrade_process() {
1223 1716 // Creating database on new installation.
1224 - $this->create_db();
1717 + ud_stateless_db()->create_db();
1718 +
1719 + Migrator::instance()->migrate();
1720 +
1225 1721 /**
1226 1722 * Maybe Upgrade current Version
1227 1723 */
1228 - Upgrader::call( $this->args[ 'version' ] );
1724 + Upgrader::call($this->args['version']);
1229 1725 }
1230 1726
1231 1727 /**
1232 - * Create database on plugin activation.
1233 - * @param boolean $force - whether to create db even if option exists. For debug purpose only.
1728 + * Delete table when blog is deleted.
1729 + *
1730 + * @param $old_site
1234 1731 */
1235 - public function create_db($force = false) {
1236 - global $wpdb;
1237 - $sm_sync_db_version = get_option( 'sm_sync_db_version' );
1238 -
1239 - if( $sm_sync_db_version && $force == false ) {
1240 - return;
1241 - }
1242 -
1243 - $table_name = $wpdb->prefix . 'sm_sync';
1244 - $charset_collate = $wpdb->get_charset_collate();
1245 -
1246 - // `expire` timestamp NULL DEFAULT NULL,
1247 - $sql = "CREATE TABLE $table_name (
1248 - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT ,
1249 - `file` varchar(255) NOT NULL ,
1250 - `status` varchar(10) NOT NULL ,
1251 - PRIMARY KEY (`id`)
1252 - ) $charset_collate;";
1253 -
1254 - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
1255 - dbDelta( $sql );
1256 -
1257 - add_option( 'sm_sync_db_version', $this->args[ 'version' ] );
1732 + public function wp_delete_site($old_site) {
1733 + ud_stateless_db()->clear_db($old_site->id);
1258 1734 }
1259 1735
1260 1736 /**
1261 1737 * Redirect_to_splash
@@ -1261,34 +1737,38 @@
1261 1737 * Redirect_to_splash
1262 1738 *
1263 1739 * @param string $plugin
1264 1740 */
1265 - public function redirect_to_splash($plugin =''){
1266 - $this->settings = new Settings();
1741 + public function redirect_to_splash($plugin = '') {
1742 + // $this->settings = new Settings();
1267 1743
1268 - 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) {
1269 1745 return;
1270 1746 }
1271 -
1272 - if(
1273 - !$this->settings->get('sm.key_json') &&
1274 - defined('WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT') && WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT == true &&
1275 - 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
1276 1752 ) {
1277 1753 return;
1278 1754 }
1279 -
1280 - 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) {
1281 1757 $url = $this->get_settings_page_url('?page=stateless-settings');
1282 - exit( wp_redirect($url));
1758 + exit(wp_redirect($url));
1283 1759 }
1284 -
1285 - if( $plugin == plugin_basename( $this->boot_file ) ) {
1286 - $url = $this->get_settings_page_url('?page=stateless-setup&step=splash-screen');
1287 - 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'))) {
1288 1767 $url = $this->get_settings_page_url('?page=stateless-settings');
1289 1768 }
1290 - exit( wp_redirect($url));
1769 +
1770 + exit( wp_redirect($url) );
1291 1771 }
1292 1772 }
1293 1773
1294 1774 /**
@@ -1294,64 +1774,102 @@
1294 1774 /**
1295 1775 * Plugin Deactivation
1296 1776 *
1297 1777 */
1298 - public function deactivate() {}
1778 + public function deactivate() {
1779 + }
1299 1780
1300 1781 /**
1301 1782 * Show_notice_stateless_cache_busting
1302 1783 *
1303 1784 */
1304 - public function show_notice_stateless_cache_busting(){
1305 - $this->errors->add( array(
1785 + public function show_notice_stateless_cache_busting() {
1786 + $this->errors->add(array(
1306 1787 'key' => 'stateless_cache_busting',
1307 1788 'button' => 'View Settings',
1308 1789 'button_link' => admin_url('upload.php?page=stateless-settings'),
1309 - 'title' => sprintf( __( "Stateless mode now requires the Cache-Busting option.", ud_get_stateless_media()->domain ) ),
1310 - 'message' => sprintf( __("WordPress looks at local files to prevent files with the same filenames.
1311 - 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.
1312 - Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain),"https://github.com/wpCloud/wp-stateless/wiki/Constants#wp_stateless_media_cache_busting", "WP_STATELESS_MEDIA_CACHE_BUSTING" ),
1313 - ), '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');
1314 1795 }
1315 1796
1316 1797 /**
1317 1798 * Filter for wp_get_attachment_url();
1318 - *
1319 1799 * @param string $url
1320 1800 * @param string $post_id
1321 1801 * @return mixed|null|string
1322 1802 */
1323 - public function wp_get_attachment_url( $url = '', $post_id = '' ) {
1324 - $sm_cloud = get_post_meta( $post_id, 'sm_cloud', 1 );
1325 - if( is_array( $sm_cloud ) && !empty( $sm_cloud[ 'fileLink' ] ) ) {
1326 - $_url = parse_url($sm_cloud[ 'fileLink' ]);
1327 - $url = !isset($_url['scheme']) ? ( 'https:' . $sm_cloud[ 'fileLink' ] ) : $sm_cloud[ 'fileLink' ];
1328 - 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 + }
1329 1839 }
1330 - return $url;
1840 +
1841 + return apply_filters('wp_stateless_attachment_url', $url, $post_id);
1331 1842 }
1332 1843
1333 1844 /**
1334 1845 * Filter for attachment_url_to_postid()
1335 - *
1846 + *
1336 1847 * @param int|false $post_id originally found post ID (or false if not found)
1337 1848 * @param string $url the URL to find the post ID for
1338 1849 * @return int|false found post ID from cloud storage URL
1339 1850 */
1340 - public function attachment_url_to_postid( $post_id, $url ) {
1851 + public function attachment_url_to_postid($post_id, $url) {
1341 1852 global $wpdb;
1342 1853
1343 - if ( ! $post_id ) {
1854 + if (!$post_id) {
1344 1855 $post_id = get_transient("stateless_url_to_postid_" . md5($url));
1345 1856
1346 - if(defined('WP_STATELESS_LEGACY_URL_TO_POSTID')){
1857 + if (defined('WP_STATELESS_LEGACY_URL_TO_POSTID')) {
1347 1858 // User can use this constant if they change the Bucket Folder (root_dir) after uploading image.
1348 1859 // This can be little slow at first run.
1349 - if(empty($post_id)){
1350 - $query = "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sm_cloud' AND meta_value LIKE '%s'";
1351 - $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 + }
1352 1870
1353 - if($post_id){
1871 + if ($post_id) {
1354 1872 set_transient("stateless_url_to_postid_" . md5($url), $post_id);
1355 1873 }
1356 1874 }
1357 1875 return $post_id;
@@ -1356,34 +1874,46 @@
1356 1874 }
1357 1875 return $post_id;
1358 1876 }
1359 1877
1360 - if(empty($post_id)){
1878 + if (empty($post_id)) {
1361 1879 $gs_base_url = $this->get_gs_host();
1362 - $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;
1363 1884 $site_url = parse_url($gs_url);
1364 - $image_path = parse_url( $url );
1885 + $image_path = parse_url($url);
1365 1886
1366 1887 //force the protocols to match if needed
1367 - if( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
1368 - $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);
1369 1890 }
1370 1891
1371 - if( 0 === strpos( $url, $gs_url . '/' ) ) {
1372 - $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 . '/'));
1373 1897 }
1374 - else if( 0 === strpos( $url, $gs_base_url . '/' ) ) {
1375 - // In case user added Bucket Folder (root_dir) after uploading image.
1376 - $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%'] . '/';
1377 1906 }
1907 + $url = $path . $url;
1378 1908
1379 1909 $sql = $wpdb->prepare(
1380 1910 "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
1381 1911 $url
1382 1912 );
1383 - $post_id = $wpdb->get_var( $sql );
1913 + $post_id = $wpdb->get_var($sql);
1384 1914
1385 - if($post_id){
1915 + if ($post_id) {
1386 1916 set_transient("stateless_url_to_postid_" . md5($url), $post_id);
1387 1917 }
1388 1918 }
1389 1919 }
@@ -1391,40 +1921,19 @@
1391 1921 return $post_id;
1392 1922 }
1393 1923
1394 1924 /**
1395 - * Upload the full size image first.
1396 - *
1397 - */
1398 - public function before_intermediate_image_sizes($sizes, $metadata = array()){
1399 - if(empty($metadata)){
1400 - return $sizes;
1401 - }
1402 -
1403 - try{
1404 - $attachment_id = attachment_url_to_postid($metadata['file']);
1405 - $this->add_media(null, $attachment_id, false, array('no_thumb' => true));
1406 - }
1407 - catch(Exception $e){
1408 -
1409 - }
1410 -
1411 - return $sizes;
1412 - }
1413 -
1414 - /**
1415 1925 * Change Upload BaseURL when CDN Used.
1416 1926 *
1417 1927 * @param $data
1418 1928 * @return mixed
1419 1929 */
1420 - public function upload_dir( $data ) {
1421 - $data[ 'basedir' ] = $this->get_gs_host();
1422 - $data[ 'baseurl' ] = $this->get_gs_host();
1423 - $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'];
1424 1934
1425 1935 return $data;
1426 -
1427 1936 }
1428 1937
1429 1938 /**
1430 1939 * Set Feature Flag constants by parsing composer.json
@@ -1433,42 +1942,39 @@
1433 1942 *
1434 1943 * @author potanin@UD
1435 1944 * @return array|mixed|null|object
1436 1945 */
1437 - public function parse_feature_flags( ) {
1946 + public function parse_feature_flags() {
1438 1947
1439 1948 try {
1440 1949
1441 - $_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');
1442 1951
1443 - $_parsed = json_decode( $_raw );
1952 + $_parsed = json_decode($_raw);
1444 1953
1445 1954 // @todo Catch poorly formatted JSON.
1446 - if( !is_object( $_parsed ) ) {
1955 + if (!is_object($_parsed)) {
1447 1956 // throw new Error( "unable to parse." );
1448 1957 }
1449 1958
1450 - foreach( (array) $_parsed->extra->featureFlags as $_feature ) {
1959 + foreach ((array) $_parsed->extra->featureFlags as $_feature) {
1451 1960
1452 - if( !defined( $_feature->constant ) ) {
1453 - define( $_feature->constant, $_feature->enabled );
1961 + if (!defined($_feature->constant)) {
1962 + define($_feature->constant, $_feature->enabled);
1454 1963
1455 - if( $_feature->enabled ) {
1456 - Utility::log( 'Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] enabled.' );
1964 + if ($_feature->enabled) {
1965 + Utility::log('Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] enabled.');
1457 1966 } else {
1458 - Utility::log( 'Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] disabled.' );
1967 + Utility::log('Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] disabled.');
1459 1968 }
1460 1969 }
1461 -
1462 1970 }
1463 -
1464 - } catch ( Exception $e ) {
1465 - 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() . ']');
1466 1973 // echo 'Caught exception: ', $e->getMessage(), "\n";
1467 1974 }
1468 1975
1469 - return isset( $_parsed ) ? $_parsed : null;
1470 -
1976 + return isset($_parsed) ? $_parsed : null;
1471 1977 }
1472 1978
1473 1979 /**
1474 1980 * Determine if Utility class contains missed function
@@ -1478,14 +1984,137 @@
1478 1984 * @param $name
1479 1985 * @param $arguments
1480 1986 * @return mixed|null
1481 1987 */
1482 - public function __call( $name, $arguments ) {
1483 - if( is_callable( array( "wpCloud\\StatelessMedia\\Utility", $name ) ) ) {
1484 - 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);
1485 1991 } else {
1486 1992 return NULL;
1487 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;
1488 2117 }
1489 2118 }
1490 2119 }
1491 2120 }