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 +308 -138 3.2.0trunk View file →
@@ -12,13 +12,16 @@
12 12 use Google\Auth\HttpHandler\HttpHandlerFactory;
13 13 use wpCloud\StatelessMedia\Sync\FileSync;
14 14 use wpCloud\StatelessMedia\Sync\ImageSync;
15 15 use wpCloud\StatelessMedia\Sync\NonLibrarySync;
16 + use wpCloud\StatelessMedia\Batch\BatchTaskManager;
16 17
17 18 if (!class_exists('wpCloud\StatelessMedia\Bootstrap')) {
18 19
19 20 final class Bootstrap extends \UsabilityDynamics\WP\Bootstrap_Plugin {
20 21
22 + const REQUIRED_PHP_VERSION = '5.5';
23 +
21 24 /**
22 25 * Google Storage Client
23 26 * Use $this->get_client()
24 27 *
@@ -51,10 +54,19 @@
51 54 * @param $args
52 55 * @author peshkov@UD
53 56 */
54 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 +
55 65 parent::__construct($args);
56 66
67 + self::$version = $args['version'] ?? self::$version;
68 +
57 69 /**
58 70 * Add custom args to api ping request
59 71 */
60 72 add_filter('ud-api-client-ping-args', function ($args, $_, $__) {
@@ -69,10 +81,12 @@
69 81 )));
70 82
71 83 // Initialize compatibility modules.
72 84 add_action('plugins_loaded', function () {
85 + Addons::instance();
73 86 new Module();
74 - });
87 + DynamicImageSupport::instance();
88 + }, 20);
75 89
76 90 /**
77 91 * Define settings and UI.
78 92 *
@@ -84,8 +98,9 @@
84 98 * Manually Update/Add option
85 99 * $this->set( 'sm.client_id', 'zxcvv12adffse' );
86 100 */
87 101 $this->settings = new Settings($this);
102 + Status::instance();
88 103 }
89 104
90 105 /**
91 106 * Prevent loading of textdomain
@@ -96,12 +111,21 @@
96 111 /**
97 112 * Instantiate class.
98 113 */
99 114 public function init() {
100 - // Parse feature falgs, set constants.
115 + // Parse feature flags, set constants.
101 116 $this->parse_feature_flags();
102 117 $sm_mode = $this->get('sm.mode');
103 118
119 + /**
120 + * Send admin email
121 + */
122 + add_action('wp_stateless_send_admin_email', array($this, 'send_admin_email'), 10, 3);
123 +
124 + // Should be created unconditionally and as early as possible to handle batch migration requests
125 + Migrator::instance();
126 + BatchTaskManager::instance();
127 +
104 128 new SyncNonMedia();
105 129
106 130 ImageSync::instance();
107 131 FileSync::instance();
@@ -115,8 +139,11 @@
115 139
116 140 // Register meta boxes and fields for media modal page
117 141 add_filter('attachment_fields_to_edit', array($this, 'attachment_modal_meta_box_callback'), 11, 2);
118 142
143 + // Get the REST API root
144 + add_filter('wp_stateless_rest_api_root', array($this, 'get_rest_api_root'));
145 +
119 146 /**
120 147 * Init hook
121 148 */
122 149 add_action('admin_init', array($this, 'admin_init'));
@@ -155,10 +182,10 @@
155 182
156 183 /**
157 184 * To prevent fatal errors for users who use PHP 5.5 or less.
158 185 */
159 - if (version_compare(PHP_VERSION, '5.5', '<')) {
160 - $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>'));
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>'));
161 188 }
162 189
163 190 /**
164 191 * Add the currently processing nag
@@ -168,9 +195,9 @@
168 195 $this->errors->add([
169 196 'title' => __('Media Library Synchronization Underway', ud_get_stateless_media()->domain),
170 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),
171 198 'button' => __('View Synchronization', ud_get_stateless_media()->domain),
172 - 'button_link' => admin_url('upload.php?page=stateless-settings#stless_sync_tab'),
199 + 'button_link' => admin_url('upload.php?page=stateless-settings&tab=stless_sync_tab'),
173 200 'key' => 'processing-in-progress'
174 201 ], 'message');
175 202 break;
176 203 }
@@ -185,13 +212,13 @@
185 212 */
186 213 $is_connected = $this->is_connected_to_gs();
187 214
188 215 if (is_wp_error($is_connected)) {
189 - $this->errors->add($is_connected->get_error_message(), 'warning');
216 + $this->errors->add($is_connected->get_error_message(), 'warning', false);
190 217 }
191 218
192 219 if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
193 - $this->errors->add($googleSDKVersionConflictError, 'warning');
220 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
194 221 }
195 222
196 223 /**
197 224 * Carry on only if we do not have errors.
@@ -212,8 +239,28 @@
212 239 add_filter('intermediate_image_sizes_advanced', array('wpCloud\StatelessMedia\Utility', 'store_can_delete_attachment'), 10, 3);
213 240 }
214 241 }
215 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 +
216 263 if ($this->get('sm.delete_remote') == 'true') {
217 264 /**
218 265 * On physical file deletion we remove any from GS
219 266 * We need priority grater than default (10) for ShortPixel plugin to work properly.
@@ -227,32 +274,53 @@
227 274 $this->_init_filters('client');
228 275 }
229 276 } elseif ($sm_mode == 'stateless') {
230 277 /**
231 - * Replacing local path to gs:// for using it on StreamWrapper
278 + * Determine if we have issues with connection to Google Storage Bucket
279 + * if SM is not disabled.
232 280 */
233 - add_filter('upload_dir', array($this, 'filter_upload_dir'), 99);
281 + $is_connected = $this->is_connected_to_gs();
234 282
235 - /**
236 - * Stateless mode working only with GD library
237 - */
238 - add_filter('wp_image_editors', array($this, 'select_wp_image_editors'));
283 + if (is_wp_error($is_connected)) {
284 + $this->errors->add($is_connected->get_error_message(), 'warning', false);
285 + }
239 286
240 - //init GS client
241 - global $gs_client;
242 - if ($gs_client = $this->init_gs_client()) {
243 - StreamWrapper::register($gs_client);
287 + if ($googleSDKVersionConflictError = get_transient("wp_stateless_google_sdk_conflict")) {
288 + $this->errors->add($googleSDKVersionConflictError, 'warning', false);
244 289 }
245 290
246 291 /**
247 - * init client's filters
292 + * Carry on only if we do not have errors.
248 293 */
249 - $this->_init_filters('client');
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);
250 299
251 - /**
252 - * init main filters
253 - */
254 - $this->_init_filters('main');
300 + /**
301 + * Stateless mode working only with GD library
302 + */
303 + add_filter('wp_image_editors', array($this, 'select_wp_image_editors'));
304 +
305 + /**
306 + * Init GS client
307 + */
308 + global $gs_client;
309 + if ($gs_client = $this->init_gs_client()) {
310 + StreamWrapper::register($gs_client);
311 + }
312 +
313 + /**
314 + * init client's filters
315 + */
316 + $this->_init_filters('client');
317 +
318 + /**
319 + * init main filters
320 + */
321 + $this->_init_filters('main');
322 + }
255 323 }
256 324 }
257 325
258 326 /**
@@ -290,14 +358,11 @@
290 358 add_filter('sanitize_file_name', array('wpCloud\StatelessMedia\Utility', 'randomize_filename'), 10);
291 359 }
292 360
293 361 /**
294 - * Override Cache Control is option is enabled
362 + * Override Cache Control if option is enabled
295 363 */
296 - $cacheControl = trim($this->get('sm.cache_control'));
297 - if (!empty($cacheControl)) {
298 - add_filter('sm:item:cacheControl', array($this, 'override_cache_control'));
299 - }
364 + add_filter('sm:item:cacheControl', array($this->settings, 'override_cache_control'));
300 365
301 366 add_filter('wp_stateless_file_name', array($this, 'handle_root_dir'), 10, 4);
302 367
303 368 /**
@@ -314,14 +379,15 @@
314 379 add_filter('wp_update_attachment_metadata', array('wpCloud\StatelessMedia\Utility', 'add_media'), 999, 2);
315 380
316 381 /**
317 382 * Delete original in the end of generating metadata
383 + * it does not work with PDF
318 384 */
319 - add_filter('wp_generate_attachment_metadata', function ($metadata, $attachment_id, $state) {
320 - if (!in_array(ud_get_stateless_media()->get('sm.mode'), array('ephemeral'))) return $metadata;
321 - @unlink(get_attached_file($attachment_id, true));
322 - return $metadata;
323 - }, 99, 3);
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);
324 390
325 391 /**
326 392 * Rewrite Image URLS
327 393 */
@@ -354,9 +420,9 @@
354 420 * @param callable|null $httpHandler
355 421 * @return StorageClient
356 422 * @throws \Exception
357 423 */
358 - public function init_gs_client(callable $httpHandler = null) {
424 + public function init_gs_client(?callable $httpHandler = null) {
359 425 // May be Loading Google SDK....
360 426 if (!class_exists('HttpHandlerFactory')) {
361 427 include_once(ud_get_stateless_media()->path('lib/Google/vendor/autoload.php', 'dir'));
362 428 }
@@ -496,9 +562,9 @@
496 562 $image['url'] = $image_src;
497 563 }
498 564 }
499 565
500 - return array_filter($sources);
566 + return is_array($sources) ? array_filter($sources) : $sources;
501 567 }
502 568
503 569 /**
504 570 * Return gs host.
@@ -529,8 +595,20 @@
529 595 return apply_filters('get_gs_host', $image_host, $image_host, $sm['bucket'], $is_ssl, $sm);
530 596 }
531 597
532 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 + /**
533 611 * Filter for wp_stateless_bucket_link if custom domain is set.
534 612 * It's get attachment url and remove "storage.googleapis.com" from url.
535 613 * So that custom url can be used.
536 614 *
@@ -567,8 +645,20 @@
567 645 return $url . $path;
568 646 }
569 647
570 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 + /**
571 661 * Get new blog settings once switched blog.
572 662 * @param $new_blog
573 663 * @param $prev_blog_id
574 664 */
@@ -637,9 +727,11 @@
637 727 public function add_custom_row_actions($actions, $post, $detached) {
638 728
639 729 if (!current_user_can('upload_files')) return $actions;
640 730
641 - $sm_cloud = get_post_meta($post->ID, 'sm_cloud', 1);
731 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $post->ID);
732 +
733 +
642 734 $sm_mode = $this->get('sm.mode');
643 735 if (!empty($sm_cloud) && $sm_mode === 'stateless') return $actions;
644 736
645 737 if ($post && 'attachment' == $post->post_type && 'image/' == substr($post->post_mime_type, 0, 6)) {
@@ -703,10 +795,22 @@
703 795 'methods' => \WP_REST_Server::CREATABLE,
704 796 'callback' => array($api_namespace, 'syncStop'),
705 797 'permission_callback' => array($api_namespace, 'authCheck')
706 798 ));
707 - }
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 + ));
708 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 +
709 813 /**
710 814 * Metabox for media modal page
711 815 * @param $form_fields
712 816 * @param $post
@@ -712,11 +816,11 @@
712 816 * @param $post
713 817 * @return array
714 818 */
715 819 public function attachment_modal_meta_box_callback($form_fields, $post) {
716 -
717 - //do not show on media edit page, only on modal
718 - if (isset($_GET['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() ) {
719 823 return $form_fields;
720 824 }
721 825
722 826 $link = get_edit_post_link($post->ID);
@@ -722,9 +826,9 @@
722 826 $link = get_edit_post_link($post->ID);
723 827
724 828 $form_field['label'] = '';
725 829 $form_field['input'] = 'html';
726 - $form_field['html'] = sprintf("<script>jQuery('.actions').prepend('<a href=\"%s#sm-attachment-metabox\">%s</a> | ')</script>", $link, __("View stateless meta", ud_get_stateless_media()->domain));
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));
727 831 $form_field['show_in_modal'] = true;
728 832
729 833 $form_fields['sm_html'] = $form_field;
730 834 return $form_fields;
@@ -757,9 +861,9 @@
757 861 * @return array
758 862 */
759 863 private function _prepare_data_for_metabox($meta_boxes, $post_id) {
760 864 $post = get_post($post_id);
761 - $sm_cloud = get_post_meta($post_id, 'sm_cloud', 1);
865 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $post_id, true);
762 866 $sm_mode = $this->get('sm.mode');
763 867
764 868 if (empty($post)) {
765 869 return $meta_boxes;
@@ -900,14 +1004,12 @@
900 1004 * @param $size
901 1005 * @return string
902 1006 */
903 1007 public function handle_root_dir($current_path, $use_root = true, $attachment_id = '', $size = '') {
904 - global $wpdb;
905 -
906 1008 //non media files
907 1009 if ($use_root === 0) {
908 - $table_name = $wpdb->prefix . 'sm_sync';
909 - $non_media = $wpdb->get_var($wpdb->prepare("SELECT file FROM {$table_name} WHERE file like '%%%s';", $current_path));
1010 + $non_media = ud_stateless_db()->get_non_library_file_name($current_path);
1011 +
910 1012 if ($non_media) {
911 1013 return $non_media;
912 1014 }
913 1015 }
@@ -1098,28 +1200,8 @@
1098 1200 return $meta;
1099 1201 }
1100 1202
1101 1203 /**
1102 - * @param $links
1103 - * @param $file
1104 - * @return mixed
1105 - */
1106 - public function plugin_action_links($links, $file) {
1107 -
1108 - if ($file == plugin_basename(dirname(__DIR__) . '/wp-stateless-media.php')) {
1109 - $settings_link = '<a href="' . '' . '">' . __('Settings', 'ssd') . '</a>';
1110 - array_unshift($links, $settings_link);
1111 - }
1112 -
1113 - if ($file == plugin_basename(dirname(__DIR__) . '/wp-stateless.php')) {
1114 - $settings_link = '<a href="' . '' . '">' . __('Settings', 'ssd') . '</a>';
1115 - array_unshift($links, $settings_link);
1116 - }
1117 -
1118 - return $links;
1119 - }
1120 -
1121 - /**
1122 1204 * Determines if plugin is loaded via mu-plugins
1123 1205 * or Network Enabled.
1124 1206 *
1125 1207 * @param bool $is_multisite
@@ -1162,29 +1244,38 @@
1162 1244 wp_register_style('wp-stateless-select2', $this->path('static/styles/select2.min.css', 'url'), array(), self::$version);
1163 1245
1164 1246 /* Attachment or upload page */
1165 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 + ]);
1166 1251
1167 1252 /* Setup wizard styles. */
1168 - wp_register_style('wp-stateless-setup-wizard', $this->path('static/styles/wp-stateless-setup-wizard.css', 'url'), array(), self::$version);
1253 + // #152
1254 + // wp_register_style('wp-stateless-setup-wizard', $this->path('static/styles/wp-stateless-setup-wizard.css', 'url'), array(), self::$version);
1169 1255
1170 1256 wp_register_script('wp-stateless-select2', ud_get_stateless_media()->path('static/scripts/select2.min.js', 'url'), array('jquery'), self::$version, true);
1171 1257
1172 1258 /* Stateless settings page */
1173 - wp_register_script('wp-stateless-settings', ud_get_stateless_media()->path('static/scripts/wp-stateless-settings.js', 'url'), array(), self::$version);
1259 + wp_register_script('wp-stateless-settings', ud_get_stateless_media()->path('static/scripts/wp-stateless-settings.js', 'url'), array('clipboard'), self::$version);
1174 1260 wp_localize_script('wp-stateless-settings', 'stateless_l10n', $this->get_l10n_data());
1175 1261
1176 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);
1177 1265
1178 1266 // Sync tab
1179 - wp_register_script('wp-stateless-angular', ud_get_stateless_media()->path('static/scripts/angular.min.js', 'url'), array(), '1.8.0', true);
1180 - wp_register_script('wp-stateless-angular-sanitize', ud_get_stateless_media()->path('static/scripts/angular-sanitize.min.js', 'url'), array('wp-stateless-angular'), '1.8.0', true);
1181 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);
1182 1268
1183 1269 wp_localize_script('wp-stateless', 'stateless_l10n', $this->get_l10n_data());
1184 1270 wp_localize_script('wp-stateless', 'wp_stateless_configs', array(
1185 1271 'WP_DEBUG' => defined('WP_DEBUG') ? WP_DEBUG : false,
1186 - 'REST_API_TOKEN' => Utility::generate_jwt_token(['user_id' => get_current_user_id()], DAY_IN_SECONDS)
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),
1187 1278 ));
1188 1279
1189 1280 $settings = ud_get_stateless_media()->get('sm');
1190 1281 $settings['wildcards'] = $this->settings->wildcards;
@@ -1193,9 +1284,16 @@
1193 1284 if (defined('WP_STATELESS_MEDIA_JSON_KEY') && WP_STATELESS_MEDIA_JSON_KEY) {
1194 1285 $settings['key_json'] = "Currently configured via a constant.";
1195 1286 }
1196 1287 wp_localize_script('wp-stateless', 'wp_stateless_settings', $settings);
1197 - wp_localize_script('wp-stateless', 'wp_stateless_compatibility', Module::get_modules());
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 + ));
1198 1296 }
1199 1297
1200 1298 /**
1201 1299 * Get_l10n_data
@@ -1237,12 +1335,14 @@
1237 1335 }
1238 1336
1239 1337 break;
1240 1338
1241 - case 'media_page_stateless-setup':
1339 + // #152
1340 + // case 'media_page_stateless-setup':
1242 1341 case 'settings_page_stateless-setup':
1243 1342 wp_enqueue_style('wp-stateless');
1244 - wp_enqueue_style('wp-stateless-setup-wizard');
1343 + // #152
1344 + // wp_enqueue_style('wp-stateless-setup-wizard');
1245 1345 break;
1246 1346 case 'media_page_stateless-settings':
1247 1347 case 'settings_page_stateless-settings':
1248 1348 wp_enqueue_style('wp-stateless');
@@ -1249,14 +1349,20 @@
1249 1349 wp_enqueue_style('wp-stateless-select2');
1250 1350 wp_enqueue_script('wp-stateless-settings');
1251 1351 wp_enqueue_script('wp-stateless-select2');
1252 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' );
1253 1356
1254 1357 // Sync tab
1255 - wp_enqueue_script('wp-stateless-angular');
1256 - wp_enqueue_script('wp-stateless-angular-sanitize');
1257 1358 wp_enqueue_script('wp-stateless');
1258 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 +
1259 1365 wp_enqueue_style('wp-pointer');
1260 1366 wp_enqueue_script('wp-pointer');
1261 1367
1262 1368 $data = array(
@@ -1262,11 +1368,11 @@
1262 1368 $data = array(
1263 1369 'key' => 'stateless-cache-busting',
1264 1370 'class' => 'notice',
1265 1371 'title' => sprintf(__("Stateless and Ephemeral modes enables and requires the Cache-Busting option.", ud_get_stateless_media()->domain)),
1266 - 'message' => sprintf(__("WordPress looks at local files to prevent files with the same filenames.
1267 - 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.
1268 - Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain), "https://wp-stateless.github.io/docs/constants/#wp_stateless_media_cache_busting", "WP_STATELESS_MEDIA_CACHE_BUSTING"),
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"),
1269 1375 );
1270 1376 echo "<script id='template-stateless-cache-busting' type='text/html'>";
1271 1377 include ud_get_stateless_media()->path('/static/views/error-notice.php', 'dir');
1272 1378 echo "</script>";
@@ -1286,10 +1392,10 @@
1286 1392 * @param $size
1287 1393 * @return mixed
1288 1394 */
1289 1395 public function wp_get_attachment_image_attributes($attr, $attachment, $size = null) {
1290 -
1291 - $sm_cloud = get_post_meta($attachment->ID, 'sm_cloud', true);
1396 +
1397 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment->ID);
1292 1398 if (is_array($sm_cloud) && !empty($sm_cloud['name'])) {
1293 1399 $attr['class'] = $attr['class'] . ' wp-stateless-item';
1294 1400 $attr['data-image-size'] = is_array($size) ? implode('x', $size) : $size;
1295 1401 $attr['data-stateless-media-bucket'] = isset($sm_cloud['bucket']) ? $sm_cloud['bucket'] : false;
@@ -1357,9 +1463,9 @@
1357 1463 * this case may happen when no local files
1358 1464 * @author korotkov@ud
1359 1465 */
1360 1466 if (!$width && !$height) {
1361 - $sm_cloud = get_post_meta($id, 'sm_cloud', true);
1467 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $id, true);
1362 1468 if (is_string($size) && !empty($sm_cloud['sizes']) && !empty($sm_cloud['sizes'][$size])) {
1363 1469 global $_wp_additional_image_sizes;
1364 1470
1365 1471 $img_url = !empty($sm_cloud['sizes'][$size]['fileLink']) ? $sm_cloud['sizes'][$size]['fileLink'] : $img_url;
@@ -1407,9 +1513,9 @@
1407 1513 public function wp_get_attachment_metadata($metadata, $attachment_id) {
1408 1514 global $default_dir;
1409 1515 $default_dir = false;
1410 1516 /* Determine if the media file has GS data at all. */
1411 - $sm_cloud = get_post_meta($attachment_id, 'sm_cloud', true);
1517 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment_id, true);
1412 1518 // If metadata not passed the get metadata from post meta.
1413 1519 if (empty($metadata)) {
1414 1520 $metadata = get_post_meta($attachment_id, '_wp_attachment_metadata', true);
1415 1521 }
@@ -1448,9 +1554,9 @@
1448 1554 if (file_exists($file_path_fix)) {
1449 1555 $metadata['file'] = "sites/$blog_id/{$metadata['file']}";
1450 1556 }
1451 1557 }
1452 - } elseif (empty($sm_cloud) && $this->get('sm.mode') == 'stateless') {
1558 + } elseif ( empty($sm_cloud) && $this->get('sm.mode') == 'stateless' && isset($metadata['file']) ) {
1453 1559 $default_dir = true;
1454 1560 $uploads = wp_get_upload_dir();
1455 1561 $default_dir = false;
1456 1562
@@ -1471,9 +1577,9 @@
1471 1577 */
1472 1578 public function get_attached_file($file, $attachment_id) {
1473 1579 global $default_dir;
1474 1580
1475 - $sm_cloud = get_post_meta($attachment_id, 'sm_cloud', true);
1581 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $attachment_id);
1476 1582 $_file = get_post_meta($attachment_id, '_wp_attached_file', true);
1477 1583
1478 1584 /* Determine if the media file has GS data at all. */
1479 1585 if (is_multisite() && $_file) {
@@ -1526,9 +1632,8 @@
1526 1632 *
1527 1633 * @author peshkov@UD
1528 1634 */
1529 1635 public function is_connected_to_gs() {
1530 -
1531 1636 $trnst = get_transient('sm::is_connected_to_gs');
1532 1637
1533 1638 if (empty($trnst) || false === $trnst || !isset($trnst['hash']) || $trnst['hash'] != md5(serialize($this->get('sm')))) {
1534 1639 $trnst = array(
@@ -1544,9 +1649,9 @@
1544 1649 } else {
1545 1650 $connected = $client->is_connected();
1546 1651 if ($connected !== true) {
1547 1652 $trnst['success'] = 'false';
1548 - $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'));
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')));
1549 1654
1550 1655 if (is_callable(array($connected, 'getHandlerContext')) && $handlerContext = $connected->getHandlerContext()) {
1551 1656 if (!empty($handlerContext['error'])) {
1552 1657 $handlerContext['error'];
@@ -1564,9 +1669,9 @@
1564 1669 set_transient('sm::is_connected_to_gs', $trnst, 4 * HOUR_IN_SECONDS);
1565 1670 }
1566 1671
1567 1672 if (isset($trnst['success']) && $trnst['success'] == 'false') {
1568 - return new \WP_Error('error', (!empty($trnst['error']) ? $trnst['error'] : __('There is an Error on connection to Google Storage.', $this->domain)));
1673 + return new \WP_Error('error', (!empty($trnst['error']) ? $trnst['error'] : 'There is an Error on connection to Google Storage.'));
1569 1674 }
1570 1675
1571 1676 return true;
1572 1677 }
@@ -1608,9 +1713,12 @@
1608 1713 * @author alim@UD
1609 1714 */
1610 1715 public function run_upgrade_process() {
1611 1716 // Creating database on new installation.
1612 - $this->create_db();
1717 + ud_stateless_db()->create_db();
1718 +
1719 + Migrator::instance()->migrate();
1720 +
1613 1721 /**
1614 1722 * Maybe Upgrade current Version
1615 1723 */
1616 1724 Upgrader::call($this->args['version']);
@@ -1616,50 +1724,14 @@
1616 1724 Upgrader::call($this->args['version']);
1617 1725 }
1618 1726
1619 1727 /**
1620 - * Create database on plugin activation.
1621 - * @param boolean $force - whether to create db even if option exists. For debug purpose only.
1622 - */
1623 - public function create_db($force = false) {
1624 - global $wpdb;
1625 - $sm_sync_db_version = get_option('sm_sync_db_version');
1626 -
1627 - if ($sm_sync_db_version && $force == false) {
1628 - return;
1629 - }
1630 -
1631 - $table_name = $wpdb->prefix . 'sm_sync';
1632 - $charset_collate = $wpdb->get_charset_collate();
1633 -
1634 - // `expire` timestamp NULL DEFAULT NULL,
1635 - $sql = "CREATE TABLE $table_name (
1636 - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT ,
1637 - `file` varchar(255) NOT NULL ,
1638 - `status` varchar(10) NOT NULL ,
1639 - PRIMARY KEY (`id`)
1640 - ) $charset_collate;";
1641 -
1642 - require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1643 - dbDelta($sql);
1644 -
1645 - add_option('sm_sync_db_version', $this->args['version']);
1646 - }
1647 -
1648 - /**
1649 1728 * Delete table when blog is deleted.
1650 1729 *
1651 1730 * @param $old_site
1652 1731 */
1653 1732 public function wp_delete_site($old_site) {
1654 - global $wpdb;
1655 -
1656 - switch_to_blog($old_site->id);
1657 - $table_name = $wpdb->prefix . 'sm_sync';
1658 -
1659 - $sql = "DROP TABLE IF EXISTS $table_name";
1660 - $wpdb->query($sql);
1661 - restore_current_blog();
1733 + ud_stateless_db()->clear_db($old_site->id);
1662 1734 }
1663 1735
1664 1736 /**
1665 1737 * Redirect_to_splash
@@ -1686,13 +1758,17 @@
1686 1758 exit(wp_redirect($url));
1687 1759 }
1688 1760
1689 1761 if ($plugin == plugin_basename($this->boot_file)) {
1690 - $url = $this->get_settings_page_url('?page=stateless-setup&step=splash-screen');
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 +
1691 1766 if (json_decode($this->settings->get('sm.key_json'))) {
1692 1767 $url = $this->get_settings_page_url('?page=stateless-settings');
1693 1768 }
1694 - exit(wp_redirect($url));
1769 +
1770 + exit( wp_redirect($url) );
1695 1771 }
1696 1772 }
1697 1773
1698 1774 /**
@@ -1711,11 +1787,11 @@
1711 1787 'key' => 'stateless_cache_busting',
1712 1788 'button' => 'View Settings',
1713 1789 'button_link' => admin_url('upload.php?page=stateless-settings'),
1714 1790 'title' => sprintf(__("Stateless mode now requires the Cache-Busting option.", ud_get_stateless_media()->domain)),
1715 - 'message' => sprintf(__("WordPress looks at local files to prevent files with the same filenames.
1716 - 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.
1717 - Override with the <a href='%s' target='_blank'>%s</a> constant.", ud_get_stateless_media()->domain), "https://wp-stateless.github.io/docs/constants/#wp_stateless_media_cache_busting", "WP_STATELESS_MEDIA_CACHE_BUSTING"),
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"),
1718 1794 ), 'notice');
1719 1795 }
1720 1796
1721 1797 /**
@@ -1725,13 +1801,13 @@
1725 1801 * @return mixed|null|string
1726 1802 */
1727 1803 public function wp_get_attachment_url($url = '', $post_id = '') {
1728 1804 global $default_dir;
1729 - $sm_cloud = get_post_meta($post_id, 'sm_cloud', 1);
1805 + $sm_cloud = apply_filters('wp_stateless_get_file', [], $post_id);
1730 1806 if (is_array($sm_cloud) && !empty($sm_cloud['fileLink'])) {
1731 1807 $_url = parse_url($sm_cloud['fileLink']);
1732 1808 $url = !isset($_url['scheme']) ? ('https:' . $sm_cloud['fileLink']) : $sm_cloud['fileLink'];
1733 - return apply_filters('wp_stateless_bucket_link', $url);
1809 + $url = apply_filters('wp_stateless_bucket_link', $url);
1734 1810 } elseif (is_multisite() && empty($sm_cloud)) {
1735 1811 $_file = get_post_meta($post_id, '_wp_attached_file', true);
1736 1812 if ($_file) {
1737 1813 if ($this->get('sm.mode') == 'stateless') {
@@ -1737,9 +1813,9 @@
1737 1813 if ($this->get('sm.mode') == 'stateless') {
1738 1814 $default_dir = true;
1739 1815 $uploads = wp_get_upload_dir();
1740 1816 $default_dir = false;
1741 - return $uploads['baseurl'] . '/' . $_file;
1817 + $url = $uploads['baseurl'] . '/' . $_file;
1742 1818 } else {
1743 1819 $uploads = wp_get_upload_dir();
1744 1820 $default_dir = false;
1745 1821 $_file = apply_filters('wp_stateless_file_name', $_file, false);
@@ -1757,12 +1833,13 @@
1757 1833 $default_dir = true;
1758 1834 $uploads = wp_get_upload_dir();
1759 1835 $default_dir = false;
1760 1836
1761 - return $uploads['baseurl'] . '/' . $_file;
1837 + $url = $uploads['baseurl'] . '/' . $_file;
1762 1838 }
1763 1839 }
1764 - return $url;
1840 +
1841 + return apply_filters('wp_stateless_attachment_url', $url, $post_id);
1765 1842 }
1766 1843
1767 1844 /**
1768 1845 * Filter for attachment_url_to_postid()
@@ -1780,10 +1857,17 @@
1780 1857 if (defined('WP_STATELESS_LEGACY_URL_TO_POSTID')) {
1781 1858 // User can use this constant if they change the Bucket Folder (root_dir) after uploading image.
1782 1859 // This can be little slow at first run.
1783 1860 if (empty($post_id)) {
1784 - $query = "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'sm_cloud' AND meta_value LIKE '%s'";
1785 - $post_id = $wpdb->get_var($wpdb->prepare($query, '%' . $url . '%'));
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 + }
1786 1870
1787 1871 if ($post_id) {
1788 1872 set_transient("stateless_url_to_postid_" . md5($url), $post_id);
1789 1873 }
@@ -1943,8 +2027,94 @@
1943 2027 unset($sizes[$_size]);
1944 2028 }
1945 2029
1946 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;
1947 2117 }
1948 2118 }
1949 2119 }
1950 2120 }