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 +1236 -642 2.3.0trunk 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';
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,105 +165,211 @@
128 165
129 166 /**
130 167 * Load WP-CLI Commands
131 168 */
132 - if( defined( 'WP_CLI' ) && WP_CLI ) {
169 + if (defined('WP_CLI') && WP_CLI) {
133 170 include_once($this->path('lib/cli/class-sm-cli-command.php', 'dir'));
134 171 }
135 172
136 - $this->is_network_detected();
173 + /**
174 + * Add scripts
175 + */
176 + add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
137 177
138 178 /**
139 - * Add scripts
179 + * Delete table when blog is deleted.
140 180 */
141 - add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
181 + add_action('wp_delete_site', array($this, 'wp_delete_site'));
142 182
143 183 /**
144 - * Hashify file name if option is enabled
184 + * To prevent fatal errors for users who use PHP 5.5 or less.
145 185 */
146 - if ( $this->get( 'sm.hashify_file_name' ) == 'true' ) {
147 - add_filter('sanitize_file_name', array( 'wpCloud\StatelessMedia\Utility', 'randomize_filename' ), 10);
186 + if (version_compare(PHP_VERSION, self::REQUIRED_PHP_VERSION, '<')) {
187 + $this->errors->add(sprintf(__('The plugin requires PHP %s or higher. You current PHP version %s is too old.', ud_get_stateless_media()->domain), '<b>' . self::REQUIRED_PHP_VERSION . '</b>', '<b>' . PHP_VERSION . '</b>'));
148 188 }
149 189
150 190 /**
151 - * Delete table when blog is deleted.
191 + * Add the currently processing nag
152 192 */
153 - add_action( 'wp_delete_site', array($this, 'wp_delete_site'));
193 + foreach (Utility::get_available_sync_classes() as $process) {
194 + if ($process->is_running()) {
195 + $this->errors->add([
196 + 'title' => __('Media Library Synchronization Underway', ud_get_stateless_media()->domain),
197 + 'message' => __('WP-Stateless is synchronizing your media library in accordance with the Mode setting. You can view progress or stop the process via the WP-Stateless Sync settings area.', ud_get_stateless_media()->domain),
198 + 'button' => __('View Synchronization', ud_get_stateless_media()->domain),
199 + 'button_link' => admin_url('upload.php?page=stateless-settings&tab=stless_sync_tab'),
200 + 'key' => 'processing-in-progress'
201 + ], 'message');
202 + break;
203 + }
204 + }
154 205
155 206 /* Initialize plugin only if Mode is not 'disabled'. */
156 - if ( $this->get( 'sm.mode' ) !== 'disabled' ) {
207 + if (($sm_mode !== 'disabled' && $sm_mode !== 'stateless') || ($sm_mode === 'stateless' && (wp_doing_ajax() || wp_doing_cron()))) {
157 208
158 209 /**
159 - * Override Cache Control is option is enabled
210 + * Determine if we have issues with connection to Google Storage Bucket
211 + * if SM is not disabled.
160 212 */
161 - $cacheControl = trim($this->get( 'sm.cache_control' ));
162 - if ( !empty($cacheControl) ) {
163 - add_filter( 'sm:item:cacheControl', array( $this, 'override_cache_control' ) );
213 + $is_connected = $this->is_connected_to_gs();
214 +
215 + if (is_wp_error($is_connected)) {
216 + $this->errors->add($is_connected->get_error_message(), 'warning', false);
164 217 }
165 218
219 + if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
220 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
221 + }
222 +
166 223 /**
224 + * Carry on only if we do not have errors.
225 + */
226 + if (!$this->has_errors()) {
227 +
228 + if (in_array($sm_mode, array('cdn', 'ephemeral', 'stateless'))) {
229 + /**
230 + * init main filters
231 + */
232 + $this->_init_filters('main');
233 + }
234 +
235 + if ($sm_mode === 'ephemeral' || $sm_mode === 'stateless') {
236 + // Store attachment id in a static variable on 'intermediate_image_sizes_advanced' filter.
237 + // Utility::store_can_delete_attachment();
238 + if (function_exists('is_wp_version_compatible') && is_wp_version_compatible('5.3-RC4-46673')) {
239 + add_filter('intermediate_image_sizes_advanced', array('wpCloud\StatelessMedia\Utility', 'store_can_delete_attachment'), 10, 3);
240 + }
241 + }
242 +
243 + if ($sm_mode === 'stateless') {
244 + /**
245 + * Replacing local path to gs:// for using it on StreamWrapper
246 + */
247 + add_filter('upload_dir', array($this, 'filter_upload_dir'), 99);
248 +
249 + /**
250 + * Stateless mode working only with GD library
251 + */
252 + add_filter('wp_image_editors', array($this, 'select_wp_image_editors'));
253 +
254 + /**
255 + * Init GS client
256 + */
257 + global $gs_client;
258 + if ($gs_client = $this->init_gs_client()) {
259 + StreamWrapper::register($gs_client);
260 + }
261 + }
262 +
263 + if ($this->get('sm.delete_remote') == 'true') {
264 + /**
265 + * On physical file deletion we remove any from GS
266 + * We need priority grater than default (10) for ShortPixel plugin to work properly.
267 + */
268 + add_filter('delete_attachment', array($this, 'remove_media'), 11);
269 + }
270 +
271 + /**
272 + * init client's filters
273 + */
274 + $this->_init_filters('client');
275 + }
276 + } elseif ($sm_mode == 'stateless') {
277 + /**
167 278 * Determine if we have issues with connection to Google Storage Bucket
168 279 * if SM is not disabled.
169 280 */
170 281 $is_connected = $this->is_connected_to_gs();
171 282
172 - if ( is_wp_error( $is_connected ) ) {
173 - $this->errors->add( $is_connected->get_error_message() );
283 + if (is_wp_error($is_connected)) {
284 + $this->errors->add($is_connected->get_error_message(), 'warning', false);
174 285 }
175 286
176 - if ( $googleSDKVersionConflictError = get_transient( "wp_stateless_google_sdk_conflict" ) ) {
177 - $this->errors->add( $googleSDKVersionConflictError, 'warning' );
287 + if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
288 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
178 289 }
179 290
180 - // To prevent fatal errors for users who use PHP 5.5 or less.
181 - if( version_compare(PHP_VERSION, '5.5', '<') ) {
182 - $this->errors->add( sprintf( __( 'The plugin requires PHP %s or higher. You current PHP version %s is too old.', ud_get_stateless_media()->domain ), '<b>5.5</b>', '<b>' . PHP_VERSION . '</b>' ) );
183 - }
184 -
185 - /** Temporary fix to WP 4.4 srcset feature **/
186 - //add_filter( 'max_srcset_image_width', function(){return 1;} );
187 -
188 291 /**
189 292 * Carry on only if we do not have errors.
190 293 */
191 - if( !$this->has_errors() ) {
294 + if (!$this->has_errors()) {
295 + /**
296 + * Replacing local path to gs:// for using it on StreamWrapper
297 + */
298 + add_filter('upload_dir', array($this, 'filter_upload_dir'), 99);
192 299
193 - if( $this->get( 'sm.mode' ) === 'cdn' || $this->get( 'sm.mode' ) === 'stateless' ) {
194 - add_filter( 'wp_get_attachment_image_attributes', array( $this, 'wp_get_attachment_image_attributes' ), 20, 3 );
195 - add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 20, 2 );
196 - add_filter( 'attachment_url_to_postid', array( $this, 'attachment_url_to_postid' ), 20, 2 );
300 + /**
301 + * Stateless mode working only with GD library
302 + */
303 + add_filter('wp_image_editors', array($this, 'select_wp_image_editors'));
197 304
198 - if ( $this->get( 'sm.body_rewrite' ) == 'true' || $this->get( 'sm.body_rewrite' ) == 'enable_editor' ) {
199 - add_filter( 'the_content', array( $this, 'the_content_filter' ), 99 );
200 - }
305 + /**
306 + * Init GS client
307 + */
308 + global $gs_client;
309 + if ($gs_client = $this->init_gs_client()) {
310 + StreamWrapper::register($gs_client);
311 + }
201 312
202 - if ( $this->get( 'sm.body_rewrite' ) == 'true' || $this->get( 'sm.body_rewrite' ) == 'enable_meta' ) {
203 - add_filter( 'get_post_metadata', array( $this, 'post_metadata_filter' ), 2, 4 );
204 - }
313 + /**
314 + * init client's filters
315 + */
316 + $this->_init_filters('client');
205 317
206 - add_filter( 'wp_stateless_bucket_link', array( $this, 'wp_stateless_bucket_link' ) );
318 + /**
319 + * init main filters
320 + */
321 + $this->_init_filters('main');
322 + }
323 + }
324 + }
325 +
326 + /**
327 + * Init additional filters which uses on all modes
328 + * @param string $type
329 + */
330 + private function _init_filters($type = '') {
331 + switch ($type) {
332 + case 'main':
333 + add_filter('wp_get_attachment_image_attributes', array($this, 'wp_get_attachment_image_attributes'), 20, 3);
334 + add_filter('wp_get_attachment_url', array($this, 'wp_get_attachment_url'), 20, 2);
335 + add_filter('get_attached_file', array($this, 'get_attached_file'), 9, 2);
336 + add_filter('attachment_url_to_postid', array($this, 'attachment_url_to_postid'), 20, 2);
337 +
338 + if ($this->get('sm.body_rewrite') == 'true' || $this->get('sm.body_rewrite') == 'enable_editor') {
339 + add_filter('the_content', array($this, 'the_content_filter'), 99);
207 340 }
208 341
209 - 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(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,130 +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 ) );
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);
627 1029
1030 + /**
1031 + * Using only filename. Other parts of path included to $root_dir.
1032 + * excluding compatibility.
1033 + */
1034 + if ($use_root) {
1035 + $current_path = basename($current_path);
1036 + }
1037 +
1038 + if (!$use_root) {
1039 + // removing the root dir if already exists in the beginning.
1040 + $raw_name = preg_replace($root_dir_regex, '', $current_path);
1041 +
1042 + if ($raw_name && is_multisite() && ($blog_id = get_current_blog_id()) != 1) {
1043 + $folder = "sites/{$blog_id}/";
1044 + if (strpos($raw_name, $folder) === 0) return $raw_name;
1045 +
1046 + return "$folder$raw_name";
1047 + }
1048 +
1049 + return $raw_name;
1050 + }
1051 +
628 1052 // skip adding root dir if it's already added.
629 - if ( $use_root && !empty( $root_dir ) && strpos($current_path, $root_dir) !== 0 ) {
630 - 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, '/ ');
631 1055 }
632 1056
633 1057 return $current_path;
634 1058 }
@@ -636,20 +1060,25 @@
636 1060 /**
637 1061 * @param $content
638 1062 * @return mixed
639 1063 */
640 - public function the_content_filter( $content ) {
1064 + public function the_content_filter($content) {
641 1065
642 - if ( $upload_data = wp_upload_dir() ) {
1066 + if ($upload_data = wp_upload_dir()) {
643 1067
644 - if ( !empty( $upload_data['baseurl'] ) && !empty( $content ) ) {
645 - $baseurl = preg_replace('/https?:\/\//','',$upload_data['baseurl']);
646 - $root_dir = trim( $this->get( 'sm.root_dir' ), '/ ' ); // Remove any forward slash and empty space.
647 - $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;
648 1074 $image_host = $this->get_gs_host();
649 1075 $file_ext = $this->replaceable_file_types();
650 - $content = preg_replace( '/(href|src)=(\'|")(https?:\/\/'.str_replace('/', '\/', $baseurl).')\/(.+?)('.$file_ext.')(\'|")/i',
651 - '$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 + );
652 1081 }
653 1082 }
654 1083
655 1084 return $content;
@@ -656,11 +1085,11 @@
656 1085 }
657 1086
658 1087 /**
659 1088 * Return file types supported by File URL Replacement.
660 - *
1089 + * @return string
661 1090 */
662 - public function replaceable_file_types(){
1091 + public function replaceable_file_types() {
663 1092 $types = $this->get('sm.body_rewrite_types');
664 1093
665 1094 // Removing extra space.
666 1095 $types = trim($types);
@@ -671,30 +1100,30 @@
671 1100 }
672 1101
673 1102 /**
674 1103 * Copied from https://developer.wordpress.org/reference/functions/get_metadata/
675 - *
1104 + *
676 1105 * @param $value null unless other filter hooked in this function.
677 1106 * @param $object_id post id
678 - * @param $meta_key
1107 + * @param $meta_key
679 1108 * @param $single
680 1109 * @return mixed
681 1110 */
682 - public function post_metadata_filter($value, $object_id, $meta_key, $single){
683 - if(empty($value)){
1111 + public function post_metadata_filter($value, $object_id, $meta_key, $single) {
1112 + if (empty($value)) {
684 1113 $meta_type = 'post';
685 1114 $transient_key = "stateless_{$meta_type}_meta";
686 -
1115 +
687 1116 $meta_cache = wp_cache_get($object_id, $transient_key);
688 - if(empty($meta_cache)){
1117 + if (empty($meta_cache)) {
689 1118 $meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
690 1119
691 - if ( !$meta_cache ) {
692 - $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));
693 1122 $meta_cache = $meta_cache[$object_id];
694 1123 }
695 -
696 - foreach($meta_cache as $key => $meta){
1124 +
1125 + foreach ($meta_cache as $key => $meta) {
697 1126 $meta_cache[$key] = array_map('maybe_unserialize', $meta_cache[$key]);
698 1127 }
699 1128
700 1129 $meta_cache = $this->convert_to_gs_link($meta_cache);
@@ -699,24 +1128,23 @@
699 1128
700 1129 $meta_cache = $this->convert_to_gs_link($meta_cache);
701 1130 wp_cache_set($object_id, $meta_cache, $transient_key);
702 1131 }
703 -
704 - if ( ! $meta_key ) {
1132 +
1133 + if (!$meta_key) {
705 1134 return $meta_cache;
706 1135 }
707 -
708 - if ( isset($meta_cache[$meta_key]) ) {
1136 +
1137 + if (isset($meta_cache[$meta_key])) {
709 1138 return $meta_cache[$meta_key];
710 1139 }
711 -
712 - // 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.
713 1142 // $value most of the time is null.
714 1143 return $value;
715 1144 }
716 1145
717 1146 return $this->convert_to_gs_link($value);
718 -
719 1147 }
720 1148
721 1149 /**
722 1150 * Replace all image link with gs link and return only if meta modified.
@@ -721,24 +1149,26 @@
721 1149 /**
722 1150 * Replace all image link with gs link and return only if meta modified.
723 1151 *
724 1152 * @param $meta
1153 + * @param $return
725 1154 * @return mixed or null when not changed.
726 1155 */
727 - public function convert_to_gs_link($meta, $return = false){
1156 + public function convert_to_gs_link($meta, $return = false) {
728 1157 $updated = $meta;
729 - if ( $meta && $upload_data = wp_upload_dir() ) {
730 - if ( !empty( $upload_data['baseurl'] ) && !empty( $meta ) ) {
731 - $baseurl = preg_replace('/https?:\/\//','',$upload_data['baseurl']);
732 - $root_dir = trim( $this->get( 'sm.root_dir' ), '/ ' ); // Remove any forward slash and empty space.
733 - $root_dir = !empty( $root_dir ) ? $root_dir . '/': false;
734 - $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 : '');
735 1165 $file_ext = $this->replaceable_file_types();
736 - $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);
737 1167 }
738 1168 }
739 1169
740 - if($updated == $meta && !$return){
1170 + if ($updated == $meta && !$return) {
741 1171 return null; // Not changed.
742 1172 }
743 1173 return $updated;
744 1174 }
@@ -746,69 +1176,54 @@
746 1176 /**
747 1177 * Replace all image link with gs link
748 1178 *
749 1179 * @param $meta
750 - * @return mixed
1180 + * @param $image_host
1181 + * @param $url
1182 + * @param $file_ext
1183 + * @return array|null|string|string[]
751 1184 */
752 - public function _convert_to_gs_link($meta, $image_host, $baseurl, $file_ext){
753 - if(is_array($meta)){
1185 + public function _convert_to_gs_link($meta, $image_host, $url, $file_ext) {
1186 + if (is_array($meta)) {
754 1187 foreach ($meta as $key => $value) {
755 - $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);
756 1189 }
757 1190 return $meta;
758 - } elseif (is_object($meta) && $meta instanceof \stdClass ) {
1191 + } elseif (is_object($meta) && $meta instanceof \stdClass) {
759 1192 foreach (get_object_vars($meta) as $key => $value) {
760 - $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);
761 1194 }
762 1195 return $meta;
763 - } elseif(is_string($meta)){
764 - 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);
765 1198 }
766 1199
767 1200 return $meta;
768 1201 }
769 1202
770 -
771 1203 /**
772 - * @param $links
773 - * @param $file
774 - * @return mixed
775 - */
776 - public function plugin_action_links( $links, $file ) {
777 -
778 - if ($file == plugin_basename( dirname( __DIR__ ) . '/wp-stateless-media.php' ) ) {
779 - $settings_link = '<a href="'. '' .'">'.__( 'Settings' , 'ssd').'</a>';
780 - array_unshift( $links, $settings_link );
781 - }
782 -
783 - if ($file == plugin_basename( dirname( __DIR__ ) . '/wp-stateless.php' ) ) {
784 - $settings_link = '<a href="'. '' .'">'.__( 'Settings' , 'ssd').'</a>';
785 - array_unshift( $links, $settings_link );
786 - }
787 -
788 - return $links;
789 - }
790 -
791 - /**
792 1204 * Determines if plugin is loaded via mu-plugins
793 1205 * or Network Enabled.
794 1206 *
1207 + * @param bool $is_multisite
1208 + * @return bool
795 1209 * @author peshkov@UD
796 1210 */
797 - public function is_network_detected() {
1211 + public function is_network_detected($is_multisite = false) {
798 1212 /* Plugin is loaded via mu-plugins. */
799 1213
800 - 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) {
801 1215 return true;
802 1216 }
803 1217
804 - if( is_multisite() ) {
1218 + if (is_multisite()) {
1219 + if ($is_multisite) return true;
805 1220 /* Looks through network enabled plugins to see if our one is there. */
806 1221 foreach (wp_get_active_network_plugins() as $path) {
807 1222 // Trying again using readlink in case it's a symlink file.
808 1223 // boot_file is already solved.
809 1224 // wp_normalize_path is helpfull in windows.
810 - 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))) {
811 1226 return true;
812 1227 }
813 1228 }
814 1229 }
@@ -820,59 +1235,65 @@
820 1235 * Register scripts and styles
821 1236 */
822 1237 public function admin_init() {
823 1238 $this->show_notice_stateless_cache_busting();
824 - 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);
825 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 +
826 1246 /* Attachment or upload page */
827 - 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 + ]);
828 1251
829 - /* Setup wizard styles and scripts. */
830 - wp_register_style( 'wp-stateless-bootstrap', $this->path( 'static/styles/bootstrap.min.css', 'url' ), array(), '3.3.7' );
831 - wp_register_style( 'bootstrap-grid-v4', $this->path( 'static/styles/bootstrap-grid.min.css', 'url' ), array(), '3.3.7' );
832 - 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);
833 1255
834 - wp_register_script( 'async.min', ud_get_stateless_media()->path( 'static/scripts/async.js', 'url' ), array(), ud_get_stateless_media()->version );
835 - wp_register_script( 'jquery.history', ud_get_stateless_media()->path( 'static/scripts/jquery.history.js', 'url' ), array( 'jquery' ), ud_get_stateless_media()->version, true );
836 - 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 );
837 - 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 );
838 - 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 );
839 - 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 );
840 - 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);
841 1257
842 - 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());
843 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);
844 1265
845 - /* Stateless settings page */
846 - wp_register_script( 'wp-stateless-settings', ud_get_stateless_media()->path( 'static/scripts/wp-stateless-settings.js', 'url' ), array(), ud_get_stateless_media()->version );
847 - wp_localize_script( 'wp-stateless-settings', 'stateless_l10n', $this->get_l10n_data() );
848 -
849 - 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);
850 1268
851 - // Sync tab
852 - if ( wp_script_is( 'jquery-ui-widget', 'registered' ) ){
853 - 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' );
854 - }
855 - else{
856 - 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' );
857 - }
858 - wp_register_script( 'wp-stateless-angular', ud_get_stateless_media()->path( 'static/scripts/angular.min.js', 'url' ), array(), '1.5.0', true );
859 - 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 );
860 - 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 );
861 -
862 - wp_localize_script( 'wp-stateless', 'stateless_l10n', $this->get_l10n_data() );
1269 + wp_localize_script('wp-stateless', 'stateless_l10n', $this->get_l10n_data());
863 1270 wp_localize_script('wp-stateless', 'wp_stateless_configs', array(
864 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),
865 1278 ));
866 -
1279 +
867 1280 $settings = ud_get_stateless_media()->get('sm');
868 - 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) {
869 1285 $settings['key_json'] = "Currently configured via a constant.";
870 1286 }
871 1287 wp_localize_script('wp-stateless', 'wp_stateless_settings', $settings);
872 - wp_localize_script('wp-stateless', 'wp_stateless_compatibility', Module::get_modules());
873 - 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' );
874 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 + ));
875 1296 }
876 1297
877 1298 /**
878 1299 * Get_l10n_data
@@ -879,10 +1300,10 @@
879 1300 *
880 1301 * @param string $value
881 1302 * @return mixed
882 1303 */
883 - public function get_l10n_data($value=''){
884 - 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');
885 1306 return $l10n;
886 1307 }
887 1308
888 1309 /**
@@ -889,24 +1310,20 @@
889 1310 * Admin Scripts
890 1311 *
891 1312 * @param $hook
892 1313 */
893 - public function admin_enqueue_scripts( $hook ) {
1314 + public function admin_enqueue_scripts($hook) {
894 1315
895 - switch( $hook ) {
1316 + switch ($hook) {
896 1317
897 1318 case 'options-media.php':
898 - //wp_enqueue_script( 'wp-api' );
1319 + wp_enqueue_style('wp-stateless');
1320 + break;
899 1321
900 - wp_enqueue_style( 'wp-stateless');
901 - wp_enqueue_script( 'wp-stateless-setup' );
902 - break;
903 -
904 1322 case 'upload.php':
1323 + wp_enqueue_style('wp-stateless');
1324 + wp_enqueue_script('wp-stateless-uploads-js');
905 1325
906 - wp_enqueue_style( 'wp-stateless');
907 - wp_enqueue_script( 'wp-stateless-uploads-js' );
908 -
909 1326 break;
910 1327
911 1328 case 'post.php':
912 1329
@@ -911,58 +1328,60 @@
911 1328 case 'post.php':
912 1329
913 1330 global $post;
914 1331
915 - if ( $post->post_type == 'attachment' ) {
916 - wp_enqueue_style( 'wp-stateless');
917 - 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');
918 1335 }
919 1336
920 1337 break;
921 1338
922 - case 'media_page_stateless-setup':
1339 + // #152
1340 + // case 'media_page_stateless-setup':
923 1341 case 'settings_page_stateless-setup':
924 - wp_enqueue_style( 'wp-stateless');
925 - wp_enqueue_style( 'wp-stateless-bootstrap' );
926 - wp_enqueue_style( 'wp-stateless-setup-wizard' );
927 -
928 - wp_enqueue_script( 'async.min' );
929 - wp_enqueue_script( 'jquery.history' );
930 - wp_enqueue_script( 'wp-stateless-validation' );
931 - wp_enqueue_script( 'wp-stateless-loading' );
932 - wp_enqueue_script( 'wp-stateless-comboBox' );
933 - wp_enqueue_script( 'wp-stateless-setup' );
934 - wp_enqueue_script( 'wp-stateless-setup-wizard-js' );
1342 + wp_enqueue_style('wp-stateless');
1343 + // #152
1344 + // wp_enqueue_style('wp-stateless-setup-wizard');
935 1345 break;
936 1346 case 'media_page_stateless-settings':
937 1347 case 'settings_page_stateless-settings':
938 - wp_enqueue_style( 'wp-stateless');
939 - wp_enqueue_script( 'wp-stateless-settings' );
940 - wp_enqueue_style( 'bootstrap-grid-v4' );
941 - wp_enqueue_style( 'wp-stateless-settings' );
942 -
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 +
943 1357 // Sync tab
944 - wp_enqueue_script( 'jquery-ui-progressbar' );
945 - wp_enqueue_script( 'wp-stateless-angular' );
946 - wp_enqueue_script( 'wp-stateless-angular-sanitize' );
947 - wp_enqueue_script( 'wp-stateless' );
948 - wp_enqueue_style( 'jquery-ui-regenthumbs' );
1358 + wp_enqueue_script('wp-stateless');
949 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 +
950 1368 $data = array(
951 - 'key' => 'stateless-cache-busting',
952 - 'class' => 'notice',
953 - 'title' => sprintf( __( "Stateless mode enables and requires the Cache-Busting option.", ud_get_stateless_media()->domain ) ),
954 - 'message' => sprintf( __("WordPress looks at local files to prevent files with the same filenames.
955 - 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.
956 - 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" ),
957 - );
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 + );
958 1376 echo "<script id='template-stateless-cache-busting' type='text/html'>";
959 - 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');
960 1378 echo "</script>";
1379 +
961 1380 break;
962 - default: break;
1381 + default:
1382 + break;
963 1383 }
964 -
965 1384 }
966 1385
967 1386 /**
968 1387 * Add Attributes to media HTML
@@ -972,20 +1391,19 @@
972 1391 * @param $attachment
973 1392 * @param $size
974 1393 * @return mixed
975 1394 */
976 - public function wp_get_attachment_image_attributes( $attr, $attachment, $size = null ) {
977 -
978 - $sm_cloud = get_post_meta( $attachment->ID, 'sm_cloud', true );
979 - if( is_array( $sm_cloud ) && !empty( $sm_cloud[ 'name' ] ) ) {
980 - $attr[ 'class' ] = $attr[ 'class' ] . ' wp-stateless-item';
981 - $attr[ 'data-image-size' ] = is_array( $size ) ? implode( 'x', $size ) : $size;
982 - $attr[ 'data-stateless-media-bucket' ] = isset( $sm_cloud[ 'bucket' ] ) ? $sm_cloud[ 'bucket' ] : false;
983 - $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'];
984 1403 }
985 1404
986 1405 return $attr;
987 -
988 1406 }
989 1407
990 1408 /**
991 1409 * Adds filter link to Media Library table.
@@ -992,10 +1410,10 @@
992 1410 *
993 1411 * @param $views
994 1412 * @return mixed
995 1413 */
996 - public function views_upload( $views ) {
997 - $views['stateless'] = '<a href="#">' . __( 'Stateless Media' ) . '</a>';
1414 + public function views_upload($views) {
1415 + $views['stateless'] = '<a href="#">' . __('Stateless Media') . '</a>';
998 1416 return $views;
999 1417 }
1000 1418
1001 1419 /**
@@ -1005,11 +1423,11 @@
1005 1423 * @param integer $id
1006 1424 * @param string $size
1007 1425 * @return mixed $false
1008 1426 */
1009 - public function image_downsize( $false = false, $id, $size ) {
1427 + public function image_downsize($false, $id, $size) {
1010 1428
1011 - 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') {
1012 1430 return $false;
1013 1431 }
1014 1432
1015 1433 /**
@@ -1014,9 +1432,9 @@
1014 1432
1015 1433 /**
1016 1434 * Check if enabled
1017 1435 */
1018 - if ( $this->get( 'sm.mode' ) !== 'cdn' && $this->get( 'sm.mode' ) !== 'stateless' ) {
1436 + if (!in_array($this->get('sm.mode'), array('cdn', 'stateless', 'ephemeral'))) {
1019 1437 return $false;
1020 1438 }
1021 1439
1022 1440 /** Start determine remote file */
@@ -1025,19 +1443,17 @@
1025 1443 $width = $height = 0;
1026 1444 $is_intermediate = false;
1027 1445
1028 1446 //** try for a new style intermediate size */
1029 - if ( $intermediate = image_get_intermediate_size( $id, $size ) ) {
1030 - if(!empty( $intermediate['gs_link'] )){
1447 + if ($intermediate = image_get_intermediate_size($id, $size)) {
1448 + if (!empty($intermediate['gs_link'])) {
1031 1449 $img_url = $intermediate['gs_link'];
1032 - }
1033 - else if(!empty( $intermediate['url'] )){
1450 + } else if (!empty($intermediate['url'])) {
1034 1451 $img_url = $intermediate['url'];
1035 - }
1036 - else{
1452 + } else {
1037 1453 $img_url = dirname($img_url) . $intermediate['file'];
1038 1454 }
1039 -
1455 +
1040 1456 $width = $intermediate['width'];
1041 1457 $height = $intermediate['height'];
1042 1458 $is_intermediate = true;
1043 1459 }
@@ -1046,18 +1462,18 @@
1046 1462 * maybe try to get images info from sm_cloud
1047 1463 * this case may happen when no local files
1048 1464 * @author korotkov@ud
1049 1465 */
1050 - if ( !$width && !$height ) {
1051 - $sm_cloud = get_post_meta( $id, 'sm_cloud', true );
1052 - 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])) {
1053 1469 global $_wp_additional_image_sizes;
1054 1470
1055 - $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;
1056 1472
1057 - if ( !empty( $_wp_additional_image_sizes[ $size ] ) ) {
1058 - $width = !empty( $_wp_additional_image_sizes[ $size ]['width'] ) ? $_wp_additional_image_sizes[ $size ]['width'] : $width;
1059 - $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;
1060 1476 }
1061 1477
1062 1478 $is_intermediate = true;
1063 1479 }
@@ -1062,9 +1478,9 @@
1062 1478 $is_intermediate = true;
1063 1479 }
1064 1480 }
1065 1481
1066 - if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
1482 + if (!$width && !$height && isset($meta['width'], $meta['height'])) {
1067 1483
1068 1484 //** any other type: use the real image */
1069 1485 $width = $meta['width'];
1070 1486 $height = $meta['height'];
@@ -1070,14 +1486,14 @@
1070 1486 $height = $meta['height'];
1071 1487 }
1072 1488
1073 1489
1074 - if ( $img_url) {
1490 + if ($img_url) {
1075 1491
1076 1492 //** we have the actual image size, but might need to further constrain it if content_width is narrower */
1077 - list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
1493 + list($width, $height) = image_constrain_size_for_editor($width, $height, $size);
1078 1494 $img_url = apply_filters('wp_stateless_bucket_link', $img_url);
1079 - return array( $img_url, $width, $height, $is_intermediate );
1495 + return array($img_url, $width, $height, $is_intermediate);
1080 1496 }
1081 1497
1082 1498
1083 1499 /**
@@ -1083,9 +1499,8 @@
1083 1499 /**
1084 1500 * All other cases work as usually
1085 1501 */
1086 1502 return $false;
1087 -
1088 1503 }
1089 1504
1090 1505 /**
1091 1506 * Extends metadata by adding GS information.
@@ -1094,38 +1509,100 @@
1094 1509 * @param $metadata
1095 1510 * @param $attachment_id
1096 1511 * @return array|mixed
1097 1512 */
1098 - 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;
1099 1516 /* Determine if the media file has GS data at all. */
1100 - $sm_cloud = get_post_meta( $attachment_id, 'sm_cloud', true );
1517 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment_id, true);
1101 1518 // If metadata not passed the get metadata from post meta.
1102 - if(empty($metadata)){
1103 - $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);
1104 1521 }
1105 1522
1106 - if(empty($metadata)){
1523 + if (empty($metadata)) {
1107 1524 $metadata = [];
1108 1525 }
1109 1526
1110 - if( is_array( $metadata ) && is_array( $sm_cloud ) && !empty( $sm_cloud[ 'fileLink' ] ) ) {
1111 - $metadata[ 'gs_link' ] = apply_filters('wp_stateless_bucket_link', $sm_cloud[ 'fileLink' ]);
1112 - $metadata[ 'gs_name' ] = isset( $sm_cloud[ 'name' ] ) ? $sm_cloud[ 'name' ] : false;
1113 - $metadata[ 'gs_bucket' ] = isset( $sm_cloud[ 'bucket' ] ) ? $sm_cloud[ 'bucket' ] : false;
1114 - if( !empty( $metadata[ 'sizes' ] ) && is_array( $metadata[ 'sizes' ] ) ) {
1115 - foreach( $metadata[ 'sizes' ] as $k => $v ) {
1116 - if( !empty( $sm_cloud[ 'sizes' ][ $k ][ 'name' ] ) ) {
1117 - $metadata['sizes'][$k]['gs_name'] = $sm_cloud[ 'sizes' ][ $k ][ 'name' ];
1118 - $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']);
1119 1536 }
1120 1537 }
1121 1538 }
1122 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;
1123 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 +
1124 1569 return $metadata;
1125 1570 }
1126 1571
1127 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 + /**
1128 1605 * Returns client object
1129 1606 * or WP_Error on failure.
1130 1607 *
1131 1608 * @author peshkov@UD
@@ -1132,24 +1609,23 @@
1132 1609 * @return object $this->client. \wpCloud\StatelessMedia\GS_Client or \WP_Error
1133 1610 */
1134 1611 public function get_client() {
1135 1612
1136 - if( null === $this->client ) {
1613 + if (null === $this->client) {
1137 1614
1138 - $key_json = $this->get( 'sm.key_json' );
1139 - if ( empty($key_json) ) {
1140 - $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');
1141 1618 }
1142 1619
1143 1620 /* Try to initialize GS Client */
1144 - $this->client = GS_Client::get_instance( array(
1145 - 'bucket' => $this->get( 'sm.bucket' ),
1621 + $this->client = GS_Client::get_instance(array(
1622 + 'bucket' => $this->get('sm.bucket'),
1146 1623 'key_json' => $key_json
1147 - ) );
1624 + ));
1148 1625 }
1149 1626
1150 1627 return $this->client;
1151 -
1152 1628 }
1153 1629
1154 1630 /**
1155 1631 * Determines if we can connect to Google Storage Bucket.
@@ -1156,47 +1632,46 @@
1156 1632 *
1157 1633 * @author peshkov@UD
1158 1634 */
1159 1635 public function is_connected_to_gs() {
1636 + $trnst = get_transient('sm::is_connected_to_gs');
1160 1637
1161 - $trnst = get_transient( 'sm::is_connected_to_gs' );
1162 -
1163 - 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')))) {
1164 1639 $trnst = array(
1165 1640 'success' => 'true',
1166 1641 'error' => '',
1167 - 'hash' => md5( serialize( $this->get( 'sm' ) ) ),
1642 + 'hash' => md5(serialize($this->get('sm'))),
1168 1643 );
1169 1644 $client = $this->get_client();
1170 1645
1171 - if ( is_wp_error( $client ) ) {
1172 - $trnst[ 'success' ] = 'false';
1173 - $trnst[ 'error' ] = $client->get_error_message();
1646 + if (is_wp_error($client)) {
1647 + $trnst['success'] = 'false';
1648 + $trnst['error'] = $client->get_error_message();
1174 1649 } else {
1175 1650 $connected = $client->is_connected();
1176 - if( $connected !== true ) {
1177 - $trnst[ 'success' ] = 'false';
1178 - $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')));
1179 1654
1180 - if( is_callable(array($connected, 'getHandlerContext')) && $handlerContext = $connected->getHandlerContext() ){
1181 - if(!empty($handlerContext['error'])){
1655 + if (is_callable(array($connected, 'getHandlerContext')) && $handlerContext = $connected->getHandlerContext()) {
1656 + if (!empty($handlerContext['error'])) {
1182 1657 $handlerContext['error'];
1183 - $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']);
1184 1659 }
1185 1660 }
1186 1661
1187 - if( is_callable(array($connected, 'getErrors')) && $error = $connected->getErrors() ){
1662 + if (is_callable(array($connected, 'getErrors')) && $error = $connected->getErrors()) {
1188 1663 $error = reset($error);
1189 - if($error['reason'] == 'accessNotConfigured')
1190 - $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']);
1191 1666 }
1192 1667 }
1193 1668 }
1194 - 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);
1195 1670 }
1196 1671
1197 - if( isset( $trnst[ 'success' ] ) && $trnst[ 'success' ] == 'false' ) {
1198 - 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.'));
1199 1674 }
1200 1675
1201 1676 return true;
1202 1677 }
@@ -1205,9 +1680,9 @@
1205 1680 * Flush all plugin transients
1206 1681 *
1207 1682 */
1208 1683 public function flush_transients() {
1209 - delete_transient( 'sm::is_connected_to_gs' );
1684 + delete_transient('sm::is_connected_to_gs');
1210 1685 }
1211 1686
1212 1687 /**
1213 1688 * Plugin Activation
@@ -1213,9 +1688,9 @@
1213 1688 * Plugin Activation
1214 1689 *
1215 1690 */
1216 1691 public function activate() {
1217 - add_action( 'activated_plugin', array($this, 'redirect_to_splash'), 99 );
1692 + add_action('activated_plugin', array($this, 'redirect_to_splash'), 99);
1218 1693 $this->run_upgrade_process();
1219 1694 }
1220 1695
1221 1696 /**
@@ -1224,10 +1699,9 @@
1224 1699 * Works on even manual plugin update.
1225 1700 *
1226 1701 * @author alim@UD
1227 1702 */
1228 - public function run_install_process()
1229 - {
1703 + public function run_install_process() {
1230 1704 // calling the upgrade function because it's same as this point for fresh install or updates.
1231 1705 $this->run_upgrade_process();
1232 1706 }
1233 1707
@@ -1237,60 +1711,27 @@
1237 1711 * Works on even manual plugin update.
1238 1712 *
1239 1713 * @author alim@UD
1240 1714 */
1241 - public function run_upgrade_process()
1242 - {
1715 + public function run_upgrade_process() {
1243 1716 // Creating database on new installation.
1244 - $this->create_db();
1717 + ud_stateless_db()->create_db();
1718 +
1719 + Migrator::instance()->migrate();
1720 +
1245 1721 /**
1246 1722 * Maybe Upgrade current Version
1247 1723 */
1248 - Upgrader::call( $this->args[ 'version' ] );
1724 + Upgrader::call($this->args['version']);
1249 1725 }
1250 1726
1251 1727 /**
1252 - * Create database on plugin activation.
1253 - * @param boolean $force - whether to create db even if option exists. For debug purpose only.
1254 - */
1255 - public function create_db($force = false) {
1256 - global $wpdb;
1257 - $sm_sync_db_version = get_option( 'sm_sync_db_version' );
1258 -
1259 - if( $sm_sync_db_version && $force == false ) {
1260 - return;
1261 - }
1262 -
1263 - $table_name = $wpdb->prefix . 'sm_sync';
1264 - $charset_collate = $wpdb->get_charset_collate();
1265 -
1266 - // `expire` timestamp NULL DEFAULT NULL,
1267 - $sql = "CREATE TABLE $table_name (
1268 - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT ,
1269 - `file` varchar(255) NOT NULL ,
1270 - `status` varchar(10) NOT NULL ,
1271 - PRIMARY KEY (`id`)
1272 - ) $charset_collate;";
1273 -
1274 - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
1275 - dbDelta( $sql );
1276 -
1277 - add_option( 'sm_sync_db_version', $this->args[ 'version' ] );
1278 - }
1279 -
1280 - /**
1281 - *
1282 1728 * Delete table when blog is deleted.
1729 + *
1730 + * @param $old_site
1283 1731 */
1284 - public function wp_delete_site($old_site){
1285 - global $wpdb;
1286 -
1287 - switch_to_blog( $old_site->id );
1288 - $table_name = $wpdb->prefix . 'sm_sync';
1289 -
1290 - $sql = "DROP TABLE IF EXISTS $table_name";
1291 - $wpdb->query($sql);
1292 - restore_current_blog();
1732 + public function wp_delete_site($old_site) {
1733 + ud_stateless_db()->clear_db($old_site->id);
1293 1734 }
1294 1735
1295 1736 /**
1296 1737 * Redirect_to_splash
@@ -1296,34 +1737,38 @@
1296 1737 * Redirect_to_splash
1297 1738 *
1298 1739 * @param string $plugin
1299 1740 */
1300 - public function redirect_to_splash($plugin =''){
1301 - $this->settings = new Settings();
1741 + public function redirect_to_splash($plugin = '') {
1742 + // $this->settings = new Settings();
1302 1743
1303 - 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) {
1304 1745 return;
1305 1746 }
1306 -
1307 - if(
1308 - !$this->settings->get('sm.key_json') &&
1309 - defined('WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT') && WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT == true &&
1310 - 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
1311 1752 ) {
1312 1753 return;
1313 1754 }
1314 -
1315 - 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) {
1316 1757 $url = $this->get_settings_page_url('?page=stateless-settings');
1317 - exit( wp_redirect($url));
1758 + exit(wp_redirect($url));
1318 1759 }
1319 -
1320 - if( $plugin == plugin_basename( $this->boot_file ) ) {
1321 - $url = $this->get_settings_page_url('?page=stateless-setup&step=splash-screen');
1322 - 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'))) {
1323 1767 $url = $this->get_settings_page_url('?page=stateless-settings');
1324 1768 }
1325 - exit( wp_redirect($url));
1769 +
1770 + exit( wp_redirect($url) );
1326 1771 }
1327 1772 }
1328 1773
1329 1774 /**
@@ -1329,64 +1774,102 @@
1329 1774 /**
1330 1775 * Plugin Deactivation
1331 1776 *
1332 1777 */
1333 - public function deactivate() {}
1778 + public function deactivate() {
1779 + }
1334 1780
1335 1781 /**
1336 1782 * Show_notice_stateless_cache_busting
1337 1783 *
1338 1784 */
1339 - public function show_notice_stateless_cache_busting(){
1340 - $this->errors->add( array(
1785 + public function show_notice_stateless_cache_busting() {
1786 + $this->errors->add(array(
1341 1787 'key' => 'stateless_cache_busting',
1342 1788 'button' => 'View Settings',
1343 1789 'button_link' => admin_url('upload.php?page=stateless-settings'),
1344 - 'title' => sprintf( __( "Stateless mode now requires the Cache-Busting option.", ud_get_stateless_media()->domain ) ),
1345 - 'message' => sprintf( __("WordPress looks at local files to prevent files with the same filenames.
1346 - 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.
1347 - 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" ),
1348 - ), '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');
1349 1795 }
1350 1796
1351 1797 /**
1352 1798 * Filter for wp_get_attachment_url();
1353 - *
1354 1799 * @param string $url
1355 1800 * @param string $post_id
1356 1801 * @return mixed|null|string
1357 1802 */
1358 - public function wp_get_attachment_url( $url = '', $post_id = '' ) {
1359 - $sm_cloud = get_post_meta( $post_id, 'sm_cloud', 1 );
1360 - if( is_array( $sm_cloud ) && !empty( $sm_cloud[ 'fileLink' ] ) ) {
1361 - $_url = parse_url($sm_cloud[ 'fileLink' ]);
1362 - $url = !isset($_url['scheme']) ? ( 'https:' . $sm_cloud[ 'fileLink' ] ) : $sm_cloud[ 'fileLink' ];
1363 - 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 + }
1364 1839 }
1365 - return $url;
1840 +
1841 + return apply_filters('wp_stateless_attachment_url', $url, $post_id);
1366 1842 }
1367 1843
1368 1844 /**
1369 1845 * Filter for attachment_url_to_postid()
1370 - *
1846 + *
1371 1847 * @param int|false $post_id originally found post ID (or false if not found)
1372 1848 * @param string $url the URL to find the post ID for
1373 1849 * @return int|false found post ID from cloud storage URL
1374 1850 */
1375 - public function attachment_url_to_postid( $post_id, $url ) {
1851 + public function attachment_url_to_postid($post_id, $url) {
1376 1852 global $wpdb;
1377 1853
1378 - if ( ! $post_id ) {
1854 + if (!$post_id) {
1379 1855 $post_id = get_transient("stateless_url_to_postid_" . md5($url));
1380 1856
1381 - if(defined('WP_STATELESS_LEGACY_URL_TO_POSTID')){
1857 + if (defined('WP_STATELESS_LEGACY_URL_TO_POSTID')) {
1382 1858 // User can use this constant if they change the Bucket Folder (root_dir) after uploading image.
1383 1859 // This can be little slow at first run.
1384 - if(empty($post_id)){
1385 - $query = "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sm_cloud' AND meta_value LIKE '%s'";
1386 - $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 + }
1387 1870
1388 - if($post_id){
1871 + if ($post_id) {
1389 1872 set_transient("stateless_url_to_postid_" . md5($url), $post_id);
1390 1873 }
1391 1874 }
1392 1875 return $post_id;
@@ -1391,34 +1874,46 @@
1391 1874 }
1392 1875 return $post_id;
1393 1876 }
1394 1877
1395 - if(empty($post_id)){
1878 + if (empty($post_id)) {
1396 1879 $gs_base_url = $this->get_gs_host();
1397 - $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;
1398 1884 $site_url = parse_url($gs_url);
1399 - $image_path = parse_url( $url );
1885 + $image_path = parse_url($url);
1400 1886
1401 1887 //force the protocols to match if needed
1402 - if( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
1403 - $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);
1404 1890 }
1405 1891
1406 - if( 0 === strpos( $url, $gs_url . '/' ) ) {
1407 - $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 . '/'));
1408 1897 }
1409 - else if( 0 === strpos( $url, $gs_base_url . '/' ) ) {
1410 - // In case user added Bucket Folder (root_dir) after uploading image.
1411 - $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%'] . '/';
1412 1906 }
1907 + $url = $path . $url;
1413 1908
1414 1909 $sql = $wpdb->prepare(
1415 1910 "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
1416 1911 $url
1417 1912 );
1418 - $post_id = $wpdb->get_var( $sql );
1913 + $post_id = $wpdb->get_var($sql);
1419 1914
1420 - if($post_id){
1915 + if ($post_id) {
1421 1916 set_transient("stateless_url_to_postid_" . md5($url), $post_id);
1422 1917 }
1423 1918 }
1424 1919 }
@@ -1426,40 +1921,19 @@
1426 1921 return $post_id;
1427 1922 }
1428 1923
1429 1924 /**
1430 - * Upload the full size image first.
1431 - *
1432 - */
1433 - public function before_intermediate_image_sizes($sizes, $metadata = array()){
1434 - if(empty($metadata)){
1435 - return $sizes;
1436 - }
1437 -
1438 - try{
1439 - $attachment_id = attachment_url_to_postid($metadata['file']);
1440 - $this->add_media(null, $attachment_id, false, array('no_thumb' => true));
1441 - }
1442 - catch(Exception $e){
1443 -
1444 - }
1445 -
1446 - return $sizes;
1447 - }
1448 -
1449 - /**
1450 1925 * Change Upload BaseURL when CDN Used.
1451 1926 *
1452 1927 * @param $data
1453 1928 * @return mixed
1454 1929 */
1455 - public function upload_dir( $data ) {
1456 - $data[ 'basedir' ] = $this->get_gs_host();
1457 - $data[ 'baseurl' ] = $this->get_gs_host();
1458 - $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'];
1459 1934
1460 1935 return $data;
1461 -
1462 1936 }
1463 1937
1464 1938 /**
1465 1939 * Set Feature Flag constants by parsing composer.json
@@ -1468,42 +1942,39 @@
1468 1942 *
1469 1943 * @author potanin@UD
1470 1944 * @return array|mixed|null|object
1471 1945 */
1472 - public function parse_feature_flags( ) {
1946 + public function parse_feature_flags() {
1473 1947
1474 1948 try {
1475 1949
1476 - $_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');
1477 1951
1478 - $_parsed = json_decode( $_raw );
1952 + $_parsed = json_decode($_raw);
1479 1953
1480 1954 // @todo Catch poorly formatted JSON.
1481 - if( !is_object( $_parsed ) ) {
1955 + if (!is_object($_parsed)) {
1482 1956 // throw new Error( "unable to parse." );
1483 1957 }
1484 1958
1485 - foreach( (array) $_parsed->extra->featureFlags as $_feature ) {
1959 + foreach ((array) $_parsed->extra->featureFlags as $_feature) {
1486 1960
1487 - if( !defined( $_feature->constant ) ) {
1488 - define( $_feature->constant, $_feature->enabled );
1961 + if (!defined($_feature->constant)) {
1962 + define($_feature->constant, $_feature->enabled);
1489 1963
1490 - if( $_feature->enabled ) {
1491 - Utility::log( 'Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] enabled.' );
1964 + if ($_feature->enabled) {
1965 + Utility::log('Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] enabled.');
1492 1966 } else {
1493 - Utility::log( 'Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] disabled.' );
1967 + Utility::log('Feature flag ' . $_feature->name . ', [' . $_feature->constant . '] disabled.');
1494 1968 }
1495 1969 }
1496 -
1497 1970 }
1498 -
1499 - } catch ( Exception $e ) {
1500 - 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() . ']');
1501 1973 // echo 'Caught exception: ', $e->getMessage(), "\n";
1502 1974 }
1503 1975
1504 - return isset( $_parsed ) ? $_parsed : null;
1505 -
1976 + return isset($_parsed) ? $_parsed : null;
1506 1977 }
1507 1978
1508 1979 /**
1509 1980 * Determine if Utility class contains missed function
@@ -1513,14 +1984,137 @@
1513 1984 * @param $name
1514 1985 * @param $arguments
1515 1986 * @return mixed|null
1516 1987 */
1517 - public function __call( $name, $arguments ) {
1518 - if( is_callable( array( "wpCloud\\StatelessMedia\\Utility", $name ) ) ) {
1519 - 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);
1520 1991 } else {
1521 1992 return NULL;
1522 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;
1523 2117 }
1524 2118 }
1525 2119 }
1526 2120 }