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