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