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