PluginProbe
UpdraftCentral Dashboard / 0.8.26
UpdraftCentral Dashboard v0.8.26
0.8.33 0.7.2 0.7.3 0.7.4 0.8.0 0.8.1 0.8.10 0.8.11 0.8.12 0.8.13 0.8.14 0.8.15 0.8.16 0.8.17 0.8.18 0.8.19 0.8.2 0.8.20 0.8.21 0.8.22 0.8.23 0.8.24 0.8.25 0.8.26 0.8.27 All 51 releases
updraftcentral / classes / class-editor.php

class-editor.php in UpdraftCentral Dashboard 0.8.26, at classes/class-editor.php

1,349 lines 48.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) die('Access denied.');
3
4 if (!class_exists('UpdraftCentral_Editor')) :
5
6 /**
7 * UpdraftCentral_Editor class.
8 *
9 * Primarily used for loading the classic and block editor resources and handles UpdraftCentral's REST
10 * requests using the block editor to edit remote pages or posts.
11 */
12 class UpdraftCentral_Editor {
13
14 public $type = '';
15
16 protected static $_instance = null;
17
18 /**
19 * Initialize prechecks and hooks for this editor class
20 *
21 * @return void
22 */
23 public function load() {
24 if (!class_exists('UpdraftCentral_REST_Posts_Controller')) include_once UD_CENTRAL_DIR.'/classes/class-rest-posts-controller.php';
25 if (!class_exists('UpdraftCentral_REST_Users_Controller')) include_once UD_CENTRAL_DIR.'/classes/class-rest-users-controller.php';
26 if (!class_exists('UpdraftCentral_REST_Taxonomies_Controller')) include_once UD_CENTRAL_DIR.'/classes/class-rest-taxonomies-controller.php';
27 if (!class_exists('UpdraftCentral_REST_Terms_Controller')) include_once UD_CENTRAL_DIR.'/classes/class-rest-terms-controller.php';
28
29 add_filter('rest_pre_dispatch', array($this, 'intercept_request_data'), 0, 3);
30 add_action('updraftcentral_load_dashboard_js', array($this, 'enqueue_editor_scripts'));
31 }
32
33 /**
34 * Creates an instance of this class. Singleton Pattern
35 *
36 * @return object Instance of this class
37 */
38 public static function instance() {
39 if (empty(self::$_instance)) {
40 self::$_instance = new self();
41 }
42
43 return self::$_instance;
44 }
45
46 /**
47 * Saves placeholder details for later use and enqueus needed resources
48 *
49 * @return void
50 */
51 public function enqueue_editor_scripts() {
52 global $post, $post_type, $post_type_object;
53
54 // We'll create a dummy post or page with status draft (if not yet created) and return its ID.
55 // We will used this post or page object to preload any scripts needed by the editor later on, since
56 // ajax-based calls will no longer have that opporturnity to load resources (which is only done during page load).
57 $post_id = $this->get_placeholder_id($this->type);
58 if (!empty($post_id)) {
59 $post = get_post($post_id);
60
61 $post_type = get_post_type($post);
62 $post_type_object = get_post_type_object($post_type);
63
64 if (!function_exists('get_current_screen')) {
65 include_once(ABSPATH . 'wp-admin/includes/screen.php');
66 include_once ABSPATH . 'wp-admin/includes/template.php';
67 }
68
69 if (!function_exists('get_page_templates')) {
70 include_once ABSPATH . 'wp-admin/includes/theme.php';
71 }
72
73 $block_patterns_file = ABSPATH.WPINC.'/block-patterns.php';
74 if (file_exists($block_patterns_file)) {
75 if (!function_exists('_register_core_block_patterns_and_categories')) {
76 include_once($block_patterns_file);
77 }
78 _register_core_block_patterns_and_categories();
79 }
80
81 $this->load_block_editor_resources();
82 }
83
84 $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
85 wp_enqueue_script('postbox', admin_url("js/postbox".$min_or_not.".js"), array('jquery-ui-sortable'), UpdraftCentral()->version, 1);
86 }
87
88 /**
89 * Loads block editor resources. Copied from wp-admin/edit-form-blocks.php (WP 5.0) and made
90 * some adjustments (remove and alter lines) to prevent loading the editor prematurely, as we need it to load
91 * on demand basing on the current page/post selected. Updated to support WP 5.4 changes.
92 *
93 * N.B. Applies to WP 5.0 and later only (that is for the core-integrated version).
94 *
95 * @return void
96 */
97 private function load_block_editor_resources() {
98 global $post_type_object, $post, $wp_meta_boxes;
99
100 // Load block patterns from w.org.
101 if (function_exists('_load_remote_block_patterns')) _load_remote_block_patterns();
102 if (function_exists('_load_remote_featured_patterns')) _load_remote_featured_patterns();
103
104 /*
105 * Emoji replacement is disabled for now, until it plays nicely with React.
106 */
107 remove_action('admin_print_scripts', 'print_emoji_detection_script');
108
109 /*
110 * Block editor implements its own Options menu for toggling Document Panels.
111 */
112 add_filter('screen_options_show_screen', '__return_false');
113
114 wp_enqueue_script('heartbeat');
115 wp_enqueue_script('wp-edit-post');
116 wp_enqueue_script('wp-format-library');
117
118 // Get admin url for handling meta boxes.
119 $meta_box_nonce = wp_create_nonce('meta-box-loader');
120
121 $meta_box_url = admin_url('post.php');
122 $meta_box_url = add_query_arg(
123 array(
124 'post' => $post->ID,
125 'action' => 'edit',
126 'meta-box-loader' => true,
127 'meta-box-loader-nonce' => $meta_box_nonce,
128 '_wpnonce' => $meta_box_nonce, // Supports legacy code prior to 5.4
129 ),
130 $meta_box_url
131 );
132 wp_add_inline_script(
133 'wp-editor',
134 sprintf('var _wpMetaBoxUrl = %s;', wp_json_encode($meta_box_url)),
135 'before'
136 );
137
138 /*
139 * Initialize the editor.
140 */
141
142 $align_wide = get_theme_support('align-wide');
143 $color_palette = current((array) get_theme_support('editor-color-palette'));
144 $font_sizes = current((array) get_theme_support('editor-font-sizes'));
145 $gradient_presets = current((array) get_theme_support('editor-gradient-presets'));
146 $custom_line_height = get_theme_support('custom-line-height');
147 $custom_units = get_theme_support('custom-units');
148
149 /**
150 * Filters the allowed block types for the editor, defaulting to true (all
151 * block types supported).
152 *
153 * @since 5.0.0
154 *
155 * @param bool|array $allowed_block_types Array of block type slugs, or
156 * boolean to enable/disable all.
157 * @param WP_Post $post The post resource data.
158 */
159 $allowed_block_types = apply_filters('allowed_block_types', true, $post);
160
161 /*
162 * Get all available templates for the post/page attributes meta-box.
163 * The "Default template" array element should only be added if the array is
164 * not empty so we do not trigger the template select element without any options
165 * besides the default value.
166 */
167 $available_templates = wp_get_theme()->get_page_templates(get_post($post->ID));
168 $available_templates = !empty($available_templates) ? array_merge(array('' => apply_filters('default_page_template_title', __('Default template'), 'rest-api')), $available_templates) : $available_templates;
169
170 // Media settings.
171 $max_upload_size = wp_max_upload_size();
172 if (!$max_upload_size) {
173 $max_upload_size = 0;
174 }
175
176 // Image sizes.
177
178 /** This filter is documented in wp-admin/includes/media.php */
179 $image_size_names = apply_filters(
180 'image_size_names_choose',
181 array(
182 'thumbnail' => __('Thumbnail'),
183 'medium' => __('Medium'),
184 'large' => __('Large'),
185 'full' => __('Full Size'),
186 )
187 );
188
189 $available_image_sizes = array();
190 foreach ($image_size_names as $image_size_slug => $image_size_name) {
191 $available_image_sizes[] = array(
192 'slug' => $image_size_slug,
193 'name' => $image_size_name,
194 );
195 }
196
197 $image_dimensions = array();
198 if (function_exists('wp_get_registered_image_subsizes')) {
199 $all_sizes = wp_get_registered_image_subsizes();
200 foreach ($available_image_sizes as $size) {
201 $key = $size['slug'];
202 if (isset($all_sizes[$key])) {
203 $image_dimensions[$key] = $all_sizes[$key];
204 }
205 }
206 }
207
208 if (!function_exists('wp_check_post_lock')) {
209 include_once ABSPATH.'wp-admin/includes/post.php';
210 }
211
212 $placeholder_editor_id = wp_check_post_lock($post->ID);
213 if ($placeholder_editor_id) {
214 // Release any lock set at the editor's placeholder. It wasn't suppose
215 // to be edited anyway because it wasn't created manually by any user.
216 delete_post_meta($post->ID, '_edit_lock');
217 }
218
219 // Lock settings.
220 $user_id = wp_check_post_lock($post->ID);
221 if ($user_id) {
222 $locked = false;
223
224 /** This filter is documented in wp-admin/includes/post.php */
225 if (apply_filters('show_post_locked_dialog', true, $post, $user_id)) {
226 $locked = true;
227 }
228
229 $user_details = null;
230 if ($locked) {
231 $user = get_userdata($user_id);
232 $user_details = array(
233 'name' => $user->display_name,
234 );
235 }
236
237 $lock_details = array(
238 'isLocked' => $locked,
239 'user' => $user_details,
240 );
241 } else {
242 // Lock the post.
243 $active_post_lock = wp_set_post_lock($post->ID);
244 if ($active_post_lock) {
245 $active_post_lock = esc_attr(implode(':', $active_post_lock));
246 }
247
248 $lock_details = array(
249 'isLocked' => false,
250 'activePostLock' => $active_post_lock,
251 );
252 }
253
254 // These styles are used if the "no theme styles" options is triggered or on
255 // themes without their own editor styles.
256 $default_editor_styles_file = ABSPATH.WPINC.'/css/dist/block-editor/default-editor-styles.css';
257 if (file_exists($default_editor_styles_file)) {
258 $default_editor_styles = array(
259 array('css' => file_get_contents($default_editor_styles_file )),
260 );
261 } else {
262 $default_editor_styles = array();
263 }
264
265 /**
266 * Filters the body placeholder text.
267 *
268 * @since 5.0.0
269 *
270 * @param string $text Placeholder text. Default 'Start writing or type / to choose a block'.
271 * @param WP_Post $post Post object.
272 */
273 $body_placeholder = apply_filters('write_your_story', __('Type / to choose a block'), $post);
274
275 $editor_settings = array(
276 'alignWide' => $align_wide,
277 'availableTemplates' => $available_templates,
278 'allowedBlockTypes' => $allowed_block_types,
279 'disableCustomColors' => get_theme_support('disable-custom-colors'),
280 'disableCustomFontSizes' => get_theme_support('disable-custom-font-sizes'),
281 'disableCustomGradients' => get_theme_support('disable-custom-gradients'),
282 'disablePostFormats' => ! current_theme_supports('post-formats'),
283 /** This filter is documented in wp-admin/edit-form-advanced.php */
284 'titlePlaceholder' => apply_filters('enter_title_here', __('Add title'), $post),
285 'bodyPlaceholder' => $body_placeholder,
286 'isRTL' => is_rtl(),
287 'autosaveInterval' => defined('AUTOSAVE_INTERVAL') ? AUTOSAVE_INTERVAL : 10,
288 'maxUploadFileSize' => $max_upload_size,
289 'allowedMimeTypes' => get_allowed_mime_types(),
290 'defaultEditorStyles' => $default_editor_styles,
291 'styles' => array(),
292 'imageSizes' => $available_image_sizes,
293 'imageDimensions' => $image_dimensions,
294 'richEditingEnabled' => user_can_richedit(),
295 'postLock' => $lock_details,
296 'postLockUtils' => array(
297 'nonce' => wp_create_nonce('lock-post_' . $post->ID),
298 'unlockNonce' => wp_create_nonce('update-post_' . $post->ID),
299 'ajaxUrl' => admin_url('admin-ajax.php'),
300 ),
301 'supportsTemplateMode' => current_theme_supports('block-templates'),
302 // N.B. We will not support custom fields for now as this will complicate things even further. Perhaps
303 // in the near future we will as the need and demand arises.
304 'enableCustomFields' => false,
305 'enableCustomLineHeight' => $custom_line_height,
306 'enableCustomUnits' => $custom_units,
307 );
308
309 if (class_exists('WP_Theme_JSON_Resolver')) {
310 $editor_settings['supportsLayout'] = WP_Theme_JSON_Resolver::theme_has_support();
311 }
312
313 if (class_exists('WP_Block_Patterns_Registry')) {
314 $editor_settings['__experimentalBlockPatterns'] = WP_Block_Patterns_Registry::get_instance()->get_all_registered();
315 }
316
317 if (class_exists('WP_Block_Pattern_Categories_Registry')) {
318 $editor_settings['__experimentalBlockPatternCategories'] = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered();
319 }
320
321 $autosave = wp_get_post_autosave($post->ID);
322 if ($autosave) {
323 if (mysql2date('U', $autosave->post_modified_gmt, false) > mysql2date('U', $post->post_modified_gmt, false)) {
324 $editor_settings['autosave'] = array(
325 'editLink' => get_edit_post_link($autosave->ID),
326 );
327 } else {
328 wp_delete_post_revision($autosave->ID);
329 }
330 }
331
332 if (false !== $color_palette) {
333 $editor_settings['colors'] = $color_palette;
334 }
335
336 if (false !== $font_sizes) {
337 $editor_settings['fontSizes'] = $font_sizes;
338 }
339
340 if (false !== $gradient_presets) {
341 $editor_settings['gradients'] = $gradient_presets;
342 }
343
344 if (!empty($post_type_object->template)) {
345 $editor_settings['template'] = $post_type_object->template;
346 $editor_settings['templateLock'] = !empty($post_type_object->template_lock) ? $post_type_object->template_lock : false;
347 }
348
349 $is_new_post = false;
350 if ('auto-draft' === $post->post_status) {
351 $is_new_post = true;
352 }
353
354 // If there's no template set on a new post, use the post format, instead.
355 if ($is_new_post && !isset($editor_settings['template']) && 'post' === $post->post_type) {
356 $post_format = get_post_format($post);
357 if (in_array($post_format, array('audio', 'gallery', 'image', 'quote', 'video'), true)) {
358 $editor_settings['template'] = array(array("core/$post_format"));
359 }
360 }
361
362 if (function_exists('wp_is_block_theme') && wp_is_block_theme() && $editor_settings['supportsTemplateMode']) {
363 if (function_exists('get_allowed_block_template_part_areas')) {
364 $editor_settings['defaultTemplatePartAreas'] = get_allowed_block_template_part_areas();
365 }
366 }
367
368 /**
369 * Scripts
370 */
371 wp_enqueue_media(
372 array(
373 'post' => $post->ID,
374 )
375 );
376 wp_tinymce_inline_scripts();
377 wp_enqueue_editor();
378
379 /**
380 * Styles
381 */
382 wp_enqueue_style('wp-edit-post');
383 wp_enqueue_style('wp-format-library');
384
385 do_action('enqueue_block_assets');
386
387 /**
388 * Fires after block assets have been enqueued for the editing interface.
389 *
390 * Call `add_action` on any hook before 'admin_enqueue_scripts'.
391 *
392 * In the function call you supply, simply use `wp_enqueue_script` and
393 * `wp_enqueue_style` to add your functionality to the block editor.
394 *
395 * @since 5.0.0
396 */
397 do_action('enqueue_block_editor_assets');
398
399 // In order to duplicate classic meta box behaviour, we need to run the classic meta box actions.
400 require_once(ABSPATH . 'wp-admin/includes/meta-boxes.php');
401 register_and_do_post_meta_boxes($post);
402
403 // Check if the Custom Fields meta box has been removed at some point.
404 if (isset($wp_meta_boxes[$post->post_type]) && isset($wp_meta_boxes[$post->post_type]['normal']) && isset($wp_meta_boxes[$post->post_type]['normal']['core'])) {
405 $core_meta_boxes = $wp_meta_boxes[$post->post_type]['normal']['core'];
406 if (!isset($core_meta_boxes['postcustom']) || !$core_meta_boxes['postcustom']) {
407 unset($editor_settings['enableCustomFields']);
408 }
409 }
410
411 if (class_exists('WP_Block_Editor_Context')) {
412 $block_editor_context = new WP_Block_Editor_Context(array('post' => $post));
413 $editor_settings = get_block_editor_settings( $editor_settings, $block_editor_context );
414 } else {
415 /**
416 * Filters the settings to pass to the block editor.
417 *
418 * @since 5.0.0
419 *
420 * @param array $editor_settings Default editor settings.
421 * @param WP_Post $post Post being edited.
422 */
423 $editor_settings = apply_filters('block_editor_settings', $editor_settings, $post);
424 }
425
426 update_user_meta(get_current_user_id(), 'updraftcentral_editor_settings', $editor_settings);
427 }
428
429 /**
430 * Retrieves the placeholder id created for the current type (e.g. 'post' or 'page')
431 *
432 * @param string $type Determines which type of ID to return (either 'post' or 'page')
433 * @return int|boolean
434 */
435 public function get_placeholder_id($type) {
436 if (in_array($type, array('page', 'post'))) {
437 $post_id = $this->maybe_create_post_and_return_id(array(
438 'post_title' => __('UpdraftCentral Editor Placeholder', 'updraftcentral'),
439 'post_name' => 'uc-editor-placeholder-'.$type,
440 'post_content' => sprintf(__('UpdraftCentral plugin uses this %s as a placeholder when loading the %s editor. You should leave it with "Draft" status.', 'updraftcentral'), $type, $type),
441 'post_status' => 'draft',
442 'post_type' => $type
443 ));
444 return $post_id;
445 }
446
447 return false;
448 }
449
450 /**
451 * Sends the command to the remote website
452 *
453 * @param int $user_id The current user ID
454 * @param string $command The command to process
455 * @param array $params The parameters that goes along with the current request
456 * @return array
457 */
458 private function send_remote_command($user_id, $command, $params) {
459 $user = UpdraftCentral()->get_user_object($user_id);
460 if (!empty($user) && !empty($params['site_id'])) {
461 $remote_params = array(
462 'site_id' => $params['site_id'],
463 'data' => array(
464 'command' => $command,
465 'data' => $params,
466 )
467 );
468
469 $remote_response = $user->send_remote_command($remote_params);
470 if (!empty($remote_response) && 'ok' == $remote_response['responsetype']) {
471 if ('rpcok' == $remote_response['rpc_response']['response']) {
472 $data = $remote_response['rpc_response']['data'];
473 return $data;
474 } elseif ('rpcerror' == $remote_response['rpc_response']['response']) {
475 return new WP_Error('updraftcentral_rpcerror', __('The remote website responded with an error.', 'updraftcentral'), $remote_response['rpc_response']['data']);
476 }
477 } else {
478 return new WP_Error('updraftcentral_communication_error', __('An error has occurred while communicating to the remote website.', 'updraftcentral'));
479 }
480 } else {
481 return new WP_Error('updraftcentral_missing_fields', __('The required object has not been found.', 'updraftcentral'));
482 }
483 }
484
485 /**
486 * Returns an instance of an UpdraftCentral_Site_Meta class that is used to manage
487 * our site meta entries
488 *
489 * @return UpdraftCentral_Site_Meta
490 */
491 private function get_site_meta_instance() {
492 $site_meta = UpdraftCentral()->site_meta;
493 if (empty($site_meta)) {
494 if (!class_exists('UpdraftCentral_Site_Meta')) include_once UD_CENTRAL_DIR.'/classes/site-meta.php';
495
496 return new UpdraftCentral_Site_Meta(UpdraftCentral()->table_prefix);
497 }
498
499 return $site_meta;
500 }
501
502 /**
503 * Intercepts request params/data and bypass default (local) processing
504 *
505 * @param mixed $response Current response, either response or `null` to indicate pass-through.
506 * @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server).
507 * @param WP_REST_Request $request The request that was used to make current response.
508 * @return WP_REST_Response
509 */
510 public function intercept_request_data($response, $handler, $request) {
511
512 // Check whether we received an updraftcentral "uc_nonce", "uc_refIds" and "site_id" and "post_type" data. This also helps in preventing any overlap
513 // or overwrites when the user is using the Block editor in the WP admin area. Thus, we're only
514 // executing the processes below if the current request is made through UpdraftCentral.
515 $params = $request->get_params();
516 if (empty($params['uc_nonce']) || empty($params['uc_refIds']) || empty($params['site_id']) || empty($params['post_type'])) return $response;
517
518 $uc_nonce = is_array($params['uc_nonce']) ? $params['uc_nonce'][0] : $params['uc_nonce'];
519 $uc_refIds = is_array($params['uc_refIds']) ? $params['uc_refIds'][0] : $params['uc_refIds'];
520 $site_id = is_array($params['site_id']) ? $params['site_id'][0] : $params['site_id'];
521 $post_type = is_array($params['post_type']) ? $params['post_type'][0] : $params['post_type'];
522
523 list($user_id, $post_id) = explode('|', base64_decode($uc_refIds));
524 if (empty($user_id) || empty($post_id)) return $response;
525
526 // Verify the nonce submitted
527 if (!wp_verify_nonce($uc_nonce, 'updraftcentral-editpost-'.$post_id)) {
528 return $response;
529 }
530
531 // Pull the (stored) preloaded information from the remote website to be use for the REST request
532 // initiated by the UpdraftCentral editor.
533 $site_meta = $this->get_site_meta_instance();
534
535 $preloaded_data = $site_meta->get_site_meta($site_id, 'updraftcentral_editor_preloaded_data_'.$post_type, true);
536 if (!empty($preloaded_data)) {
537 if (isset($preloaded_data['post_data'])) {
538 $post_data = $preloaded_data['post_data'];
539 $post = $this->setup_remotepost_data($post_data['post'], true);
540 }
541 }
542
543 $match_result = preg_match('#^/wp/v2/(pages|posts)/([0-9]+)#', $request->get_route(), $matches);
544 if (!empty($match_result) && $post) {
545 $params = $request->get_params();
546 $post_id = $matches[2];
547
548 switch ($request->get_method()) {
549 case 'GET':
550 $controller = new UpdraftCentral_REST_Posts_Controller($post->post_type);
551 $misc = $this->attach_media_to_post($post_data['misc'], $post);
552
553 $response = $controller->prepare_remote_item_for_response($post, $request, $misc);
554 break;
555 case 'PUT':
556 if (!empty($params['featured_media'])) {
557 $params['featured_media_url'] = wp_get_attachment_url($params['featured_media']);
558 $dir = wp_upload_dir();
559
560 $image_info = wp_get_attachment_metadata($params['featured_media'], true);
561 if (is_array($image_info) && !empty($image_info['file'])) {
562 $image_file = trailingslashit($dir['basedir']).$image_info['file'];
563 if (file_exists($image_file)) {
564 $params['featured_media_data'] = base64_encode(file_get_contents($image_file, false, null));
565 }
566 }
567 }
568
569 $command = ('pages' == $matches[1]) ? 'pages.save' : 'posts.save';
570 if (!isset($request['context'])) $request['context'] = 'edit';
571
572 // On latest WP (e.g. 5.6) 'menu_order' is passed by the block editor instead of 'order', thus, we need
573 // to make sure that it is compatible with our service handler.
574 if (isset($params['menu_order'])) $params['order'] = $params['menu_order'];
575
576 // On latest WP (e.g. 5.6) a NULL value is passed instead of zero, thus, we'll make some
577 // adjustment before sending it to our service handler for compatibility.
578 //
579 // N.B. Running the check directly with "isset" and "empty" won't work since we need to make
580 // sure that we will only process if the fields were actually edited and the block editor will
581 // only send the fields of those edited post or page properties. Thus, we used the "array_key_exists"
582 // method here before checking if the value is NULL.
583 if (array_key_exists('parent', $params) && is_null($params['parent'])) $params['parent'] = 0;
584
585 $data = $this->send_remote_command($user_id, $command, $params);
586 if (!is_wp_error($data) && !empty($data)) {
587 $post = json_decode($data['post']);
588 $misc = $this->attach_media_to_post($data['misc'], $post);
589
590 // Update/replace existing preloaded post data with the recent
591 // changes so that it gets reflected all throughout UpdraftCentral.
592 $post_data = array(
593 'post' => $post,
594 'misc' => $misc
595 );
596
597 $preloaded_data['post_data'] = $post_data;
598 $site_meta->update_site_meta($site_id, 'updraftcentral_editor_preloaded_data_'.$post_type, $preloaded_data);
599
600 if (!empty($data['options'])) {
601 $post_data['options'] = $data['options'];
602 }
603
604 // Generate the response
605 $controller = new UpdraftCentral_REST_Posts_Controller($post->post_type);
606 $response = $controller->prepare_remote_item_for_response($post, $request, $misc);
607
608 $response_data = $response->get_data();
609 if (!empty($response_data)) {
610 // We need to add the post_data field to the response in order
611 // to update the current list item's information
612 $response_data['post_data'] = $post_data;
613 $response->set_data($response_data);
614 }
615 } else {
616 if (is_wp_error($data)) {
617 // Default message if we can't pull any relevant error messages from $data
618 $error_message = __('An unknown error has occurred while processing your request. Please contact our support on updraftplus.com so that we can properly escalate the issue.', 'updraftcentral');
619
620 $messages = $data->get_error_messages();
621 if (!empty($messages)) {
622 $error_message = $messages[0];
623 }
624
625 // More specific error information - will override any previous one
626 $error_data = $data->get_error_data();
627 if (isset($error_data['data']) && isset($error_data['data']['message'])) {
628 $error_message = $error_data['data']['message'];
629 }
630
631 return new WP_Error('rest_remote_save_failed', $error_message);
632 } else {
633 return new WP_Error('rest_remote_save_failed', __('An unknown error has occurred while processing your request. Please contact our support on updraftplus.com so that we can properly escalate the issue.', 'updraftcentral'));
634 }
635 }
636 break;
637 }
638 }
639
640 if ('/wp/v2/users' == $request->get_route() && 'GET' == $request->get_method()) {
641 $data = $preloaded_data['authors'];
642
643 $items = array();
644 foreach ($data as $item) {
645 $remote_item = json_decode($item['user']);
646
647 $controller = new UpdraftCentral_REST_Users_Controller;
648 $response = $controller->prepare_remote_item_for_response($remote_item, $request, $item['misc']);
649
650 $merged_data = array_merge($response->get_data(), array('_links' => $response->get_links()));
651 array_push($items, $merged_data);
652 }
653
654 $response = new WP_REST_Response($items);
655 }
656
657 if ('/wp/v2/pages' == $request->get_route() && 'GET' == $request->get_method()) {
658 $data = $preloaded_data['parent_pages'];
659
660 $items = array();
661 foreach ($data as $item) {
662 $remote_item = json_decode($item['post']);
663 if ($post && $remote_item && $post->ID != $remote_item->ID) {
664 $controller = new UpdraftCentral_REST_Posts_Controller($remote_item->post_type);
665 $response = $controller->prepare_remote_item_for_response($remote_item, $request, $item['misc']);
666
667 $merged_data = array_merge($response->get_data(), array('_links' => $response->get_links()));
668 array_push($items, $merged_data);
669 }
670 }
671
672 $response = new WP_REST_Response($items);
673 }
674
675 if ('/wp/v2/taxonomies' == $request->get_route() && 'GET' == $request->get_method()) {
676 $controller = new UpdraftCentral_REST_Taxonomies_Controller;
677 if (isset($preloaded_data['taxonomies'])) {
678 $data = $preloaded_data['taxonomies'];
679
680 $taxonomies = isset($data['taxonomies']) ? $data['taxonomies'] : array();
681 if (!empty($taxonomies) && is_array($taxonomies)) {
682 foreach ($taxonomies as $key => $value) {
683 $tax = $controller->prepare_remote_item_for_response($value, $request);
684 $taxonomies[$key] = $controller->prepare_response_for_collection($tax);
685 }
686 }
687
688 $response = new WP_REST_Response($taxonomies);
689 }
690 }
691
692 $match_result = preg_match('#^/wp/v2/taxonomies/(.*)#', $request->get_route(), $matches);
693 if (!empty($match_result) && 'GET' == $request->get_method()) {
694 $taxonomy = $matches[1];
695
696 $controller = new UpdraftCentral_REST_Taxonomies_Controller;
697 if (isset($preloaded_data['taxonomies'])) {
698 $data = $preloaded_data['taxonomies'];
699
700 $result = array();
701 $taxonomies = isset($data['taxonomies']) ? $data['taxonomies'] : array();
702 if (!empty($taxonomies) && is_array($taxonomies)) {
703 foreach ($taxonomies as $key => $value) {
704 $tax = $controller->prepare_remote_item_for_response($value, $request);
705 $taxonomies[$key] = $controller->prepare_response_for_collection($tax);
706 }
707
708 if (!empty($taxonomy) && isset($taxonomies[$taxonomy])) {
709 // For individual taxonomy retrieval
710 $result = $taxonomies[$taxonomy];
711 if (!empty($params['context']) && 'edit' === $params['context']) {
712 if (isset($result['_links'])) unset($result['_links']);
713 }
714 }
715 }
716
717 $response = new WP_REST_Response($result);
718 }
719 }
720
721 if ('/wp/v2/categories' == $request->get_route() && 'GET' == $request->get_method()) {
722 $controller = new UpdraftCentral_REST_Terms_Controller('category');
723 $taxonomies = $preloaded_data['taxonomies']['taxonomies'];
724
725 $terms = array();
726 $categories = isset($preloaded_data['categories']) ? $preloaded_data['categories'] : array();
727 if (!empty($categories) && is_array($categories)) {
728 $terms = $categories['terms'];
729 foreach ($terms as $key => $value) {
730 if (isset($value['term'])) {
731 $term = json_decode($value['term']);
732
733 $misc = $value['misc'];
734 $misc['taxonomy_obj'] = $taxonomies[$misc['taxonomy']];
735
736 $item = $controller->prepare_remote_item_for_response($term, $request, $misc);
737 $terms[$key] = $controller->prepare_response_for_collection($item);
738 }
739 }
740 }
741
742 $response = new WP_REST_Response($terms);
743 }
744
745 if ('/wp/v2/tags' == $request->get_route() && 'GET' == $request->get_method()) {
746 $controller = new UpdraftCentral_REST_Terms_Controller('post_tag');
747 $taxonomies = $preloaded_data['taxonomies']['taxonomies'];
748
749 $terms = array();
750 $tags = isset($preloaded_data['tags']) ? $preloaded_data['tags'] : array();
751 if (!empty($tags) && is_array($tags)) {
752 $terms = $tags['terms'];
753
754 foreach ($terms as $key => $value) {
755 if (isset($value['term'])) {
756 $term = json_decode($value['term']);
757 $misc = $value['misc'];
758 $misc['taxonomy_obj'] = $taxonomies[$misc['taxonomy']];
759
760 $item = $controller->prepare_remote_item_for_response($term, $request, $misc);
761 $terms[$key] = $controller->prepare_response_for_collection($item);
762 }
763 }
764 }
765
766 $response = new WP_REST_Response($terms);
767 }
768
769 if ('/wp/v2/categories' == $request->get_route() && 'POST' === $request->get_method()) {
770 $data = $this->send_remote_command($user_id, 'posts.add_category', $params);
771 if (!is_wp_error($data) && !empty($data)) {
772 $categories = json_decode($data['categories'], true);
773
774 // Update preloaded data:
775 $preloaded_data['categories'] = $categories;
776 $site_meta->update_site_meta($site_id, 'updraftcentral_editor_preloaded_data_'.$post_type, $preloaded_data);
777
778 unset($data['categories']);
779 $response = new WP_REST_Response($data);
780 }
781 }
782
783 if ('/wp/v2/tags' == $request->get_route() && 'POST' === $request->get_method()) {
784 $data = $this->send_remote_command($user_id, 'posts.add_tag', $params);
785 if (!is_wp_error($data) && !empty($data)) {
786 $tags = json_decode($data['tags'], true);
787
788 // Update preloaded data:
789 $preloaded_data['tags'] = $tags;
790 $site_meta->update_site_meta($site_id, 'updraftcentral_editor_preloaded_data_'.$post_type, $preloaded_data);
791
792 unset($data['tags']);
793 $response = new WP_REST_Response($data);
794 }
795 }
796
797 return $response;
798 }
799
800 /**
801 * Creates a new post or return the ID of the existing post
802 *
803 * @param array $data An array of information needed to create a new post if applicable
804 * @return int|bool
805 */
806 private function maybe_create_post_and_return_id($data) {
807 global $wpdb;
808 $query = $wpdb->prepare('SELECT ID FROM '.$wpdb->posts.' WHERE post_name = %s', $data['post_name']);
809 $wpdb->query($query);
810
811 if ($wpdb->num_rows) {
812 $post_id = intval($wpdb->get_var($query));
813 } else {
814 $post_id = wp_insert_post($data);
815 }
816
817 if (is_wp_error($post_id) || empty($post_id)) return false;
818 return $post_id;
819 }
820
821 /**
822 * Loads metaboxees for the classic editor
823 *
824 * @param string $post_type Type of the post submitted
825 * @param WP_Post $post A WP_Post object
826 * @return void
827 */
828 public function load_metaboxes($post_type, $post) {
829 global $post_type_object;
830
831 add_meta_box('submitdiv', __('Publish', 'updraftcentral'), 'post_submit_meta_box', $post->post_type, 'side', 'core', null);
832
833 if ('page' == $post->post_type) {
834 if (post_type_supports($post->post_type, 'page-attributes') || count(get_page_templates($post)) > 0) {
835 add_meta_box('pageparentdiv', $post_type_object->labels->attributes, 'page_attributes_meta_box', $post->post_type, 'side', 'core');
836 }
837 } else {
838 add_meta_box('categorydiv', __('Categories', 'updraftcentral'), array($this, 'post_categories_meta_box'), $post->post_type, 'side', 'core', null);
839
840 add_meta_box('tagsdiv-post_tag', __('Tags', 'updraftcentral'), array($this, 'post_tags_meta_box'), $post->post_type, 'side', 'core', null);
841 }
842
843 if (post_type_supports($post->post_type, 'thumbnail') && current_user_can('upload_files')) {
844 add_meta_box('postimagediv', esc_html($post_type_object->labels->featured_image), 'post_thumbnail_meta_box', $post->post_type, 'side', 'low');
845 }
846 }
847
848 /**
849 * Fetch parent pages for the particular post object (applicable to 'page' post type)
850 *
851 * @return array
852 */
853 public function load_remote_pages() {
854 global $post, $site_id;
855
856 $user = UpdraftCentral()->get_user_object(get_current_user_id());
857 $remote_params = array(
858 'site_id' => $site_id,
859 'data' => array(
860 'command' => 'pages.get_parent_pages',
861 'data' => array(
862 'page' => 1,
863 'per_page' => 100,
864 'exclude' => array($post->ID),
865 'order' => 'ASC',
866 'orderby' => 'menu_order',
867 'status' => 'publish'
868 ),
869 )
870 );
871
872 $remote_response = $user->send_remote_command($remote_params);
873 if (!empty($remote_response) && 'ok' == $remote_response['responsetype']) {
874 if ('rpcok' == $remote_response['rpc_response']['response']) {
875 $data = $remote_response['rpc_response']['data'];
876 return $data['pages'];
877 }
878 }
879
880 return array();
881 }
882
883 /**
884 * Setup the global post data so that any underlying processes will
885 * get to see and acknowledge the remote post as the current object
886 *
887 * @param array $post_data The current post data to edit
888 * @param bool $disable_screen Whether to disable setting the screen or not
889 * @return WP_Post
890 */
891 private function setup_remotepost_data($post_data, $disable_screen = false) {
892 global $post;
893
894 // We need to setup and cache this edited post data so that other processes
895 // or hooks that will eventually rely on this information will succeed.
896 $post = new WP_Post((object) $post_data);
897 if ($post) {
898 setup_postdata($post);
899 if (!$disable_screen) {
900 set_current_screen($post->post_type);
901 }
902
903 // Make sure that this new object gets inserted into the cache
904 // otherwise, WP won't be able to see this information as these are
905 // coming from the remote website and not a local WP_Post object.
906 //
907 // N.B. This will bypass checking the post information from the database
908 // which in reality doesn't actually exists locally since it is coming from
909 // the remote website.
910 wp_cache_set($post->ID, $post, 'posts');
911 }
912
913 return $post;
914 }
915
916 /**
917 * Extracts preloaded information (styles) by key
918 *
919 * @param array $editor_styles The preloaded editor styles array
920 * @param string $key The key or name of the data to extract
921 *
922 * @return mixed|false
923 */
924 private function filter_preloaded_styles($editor_styles, $key) {
925 $result = array_values(array_filter($editor_styles, function($item) use ($key) {
926 return isset($item[$key]);
927 }));
928
929 if (!empty($result)) {
930 return $result[0][$key];
931 }
932 return false;
933 }
934
935 /**
936 * Store preloaded data from remote which will be accessed later, making succeeding
937 * access to these information much more faster the next time around.
938 *
939 * @param array $params The parameters that goes along with the current request
940 * @return void
941 */
942 public function maybe_store_preloaded_data($params) {
943
944 $data = array();
945 // Preloaded data such as remote taxonomies, categories and tags are stored here if
946 // they exists as not to redo the whole request when a new REST request is executed.
947 if (!empty($params['preloaded_data'])) {
948 $data = json_decode($params['preloaded_data'], true);
949 }
950
951 if (!empty($params['post_data'])) {
952 global $post, $post_data;
953
954 // We might as well store the currently edited post here so that any succeeding REST
955 // request for this particular `post` information will no longer require us to initiate another request
956 // just for getting the same information from the remote website (which is kind of redundant
957 // since we've already got those data loaded in the first place).
958 $post_data = json_decode($params['post_data'], true);
959 $data['post_data'] = $post_data;
960
961 // Setup remote post for local access
962 $post = $this->setup_remotepost_data($post_data['post']);
963 }
964
965 // Store preloaded data as user meta, thus, making them unique for every user wanting
966 // to edit their own remote posts or pages.
967 if (!empty($data) && !empty($params['site_id'])) {
968 global $site_id;
969
970 $site_id = $params['site_id'];
971 $site_meta = $this->get_site_meta_instance();
972 $site_meta->update_site_meta($site_id, 'updraftcentral_editor_preloaded_data_'.$post->post_type, $data);
973 }
974 }
975
976 /**
977 * Loads the Gutenberg needed information to successfully load the block
978 * editor in the client.
979 *
980 * @param array $params A collection of information needed when loading the editor
981 * @return array
982 */
983 public function load_gutenberg_editor($params) {
984 global $post, $post_data;
985
986 // Store preloaded data if not yet been stored.
987 $this->maybe_store_preloaded_data($params);
988
989 ob_start();
990 the_block_editor_meta_boxes();
991 $metaboxes = ob_get_contents();
992 ob_end_clean();
993
994 $nonce = wp_create_nonce('updraftcentral-editpost-'.$post->ID);
995 $info = array(
996 'uc_nonce' => $nonce,
997 'uc_refIds' => base64_encode(get_current_user_id().'|'.$post->ID)
998 );
999
1000 $settings = get_user_meta(get_current_user_id(), 'updraftcentral_editor_settings', true);
1001
1002 if (isset($params['preloaded_data'])) {
1003 $preloaded_data = json_decode($params['preloaded_data'], true);
1004 $editor_styles = $preloaded_data['editor_styles'];
1005
1006 $filter_map = array(
1007 'styles' => 'editor_css',
1008 'fonts' => 'font_css',
1009 'theme_fonts' => 'theme_json_fonts',
1010 'defaultEditorStyles' => 'default_editor_css',
1011 'editor_assets' => 'editor_assets',
1012 );
1013
1014 foreach ($filter_map as $key => $value) {
1015 $filtered_data = $this->filter_preloaded_styles($editor_styles, $value);
1016 if (!empty($filtered_data)) $settings[$key] = $filtered_data;
1017 }
1018 }
1019
1020 $settings['availableTemplates'] = array();
1021 if (isset($settings['availableTemplates']) && !empty($params['template_options'])) {
1022 $templates = array();
1023 $options = $params['template_options'];
1024
1025 if (!empty($options)) {
1026 foreach ($options as $value) {
1027 $templates[$value['filename']] = $value['template'];
1028 }
1029 }
1030
1031 $settings['availableTemplates'] = array_merge(array('' => __('Default template', 'updraftcentral')), $templates);
1032 }
1033
1034 $misc = $this->attach_media_to_post($post_data['misc'], $post);
1035
1036 $preloaded = json_decode($params['preloaded_data'], true);
1037 $block_categories = get_block_categories($post);
1038 $block_definitions = get_block_editor_server_block_settings();
1039
1040 if (!empty($preloaded)) {
1041 if (isset($preloaded['block_patterns']) && isset($preloaded['block_pattern_categories'])) {
1042 $settings['__experimentalBlockPatterns'] = $preloaded['block_patterns'];
1043 $settings['__experimentalBlockPatternCategories'] = $preloaded['block_pattern_categories'];
1044 }
1045
1046 $block_categories = $preloaded['block_categories'];
1047 $block_definitions = $preloaded['block_definitions'];
1048 }
1049
1050 return array(
1051 'post' => $post,
1052 'misc' => $misc,
1053 'logo' => trailingslashit(UD_CENTRAL_URL).'images/updraftcentral-logo-landscape.png',
1054 'metaboxes' => $metaboxes,
1055 'settings' => $settings,
1056 'info' => $info,
1057 'has_upload_permissions' => current_user_can('upload_files'), // N.B. We're using the local media library interface when uploading/editing the featured image, so we need to check whether the UpdraftCentral user have the "upload_files" permission. Otherwise, the user won't be able to edit the featured image of a post or page or upload a new one for that matter.
1058 'block_categories' => $block_categories,
1059 'block_definitions' => $block_definitions,
1060 );
1061 }
1062
1063 /**
1064 * Loads the Classic Editor
1065 *
1066 * @param array $params A collection of information needed when loading the editor
1067 * @return array
1068 */
1069 public function load_classic_editor($params) {
1070 global $post_type_object, $post, $site_id, $uc_categories_meta_box, $uc_tags_meta_box, $post_data;
1071
1072 // Store preloaded data if not yet been stored.
1073 $this->maybe_store_preloaded_data($params);
1074
1075 $item = $post_data['misc'];
1076 $site_id = $params['site_id'];
1077 $data = array();
1078
1079 if (!empty($item)) {
1080 if ($post) {
1081 include_once ABSPATH . 'wp-admin/includes/meta-boxes.php';
1082 include_once ABSPATH . 'wp-admin/includes/template.php';
1083
1084 $item = $this->attach_media_to_post($item, $post);
1085 $post_type_object = get_post_type_object($post->post_type);
1086 set_current_screen($post->post_type);
1087
1088 // Make sure that we add the necessary metaboxes for our current post_type (e.g. page or post)
1089 // before actually rendering them.
1090 add_action('add_meta_boxes', array($this, 'load_metaboxes'), 10, 2);
1091 do_action('add_meta_boxes', $post->post_type, $post);
1092
1093 // Grab editor content to put inside a variable
1094 ob_start();
1095 wp_editor($post->post_content, 'uc_classic_editor');
1096 $editor = ob_get_contents();
1097 ob_end_clean();
1098
1099 // Now grab the metaboxes content
1100 ob_start();
1101 do_meta_boxes($post->post_type, 'side', $post);
1102 $metaboxes = ob_get_contents();
1103 ob_end_clean();
1104
1105 $data = array(
1106 'post' => $post,
1107 'misc' => $item,
1108 'logo' => trailingslashit(UD_CENTRAL_URL).'images/updraftcentral-logo-landscape.png',
1109 'editor' => $editor,
1110 'metaboxes' => $metaboxes,
1111 'tags_metabox_content' => $uc_tags_meta_box,
1112 'categories_metabox_content' => $uc_categories_meta_box
1113 );
1114 }
1115 }
1116
1117 return $data;
1118 }
1119
1120 /**
1121 * Searches for the media ID of a given attachment/image
1122 *
1123 * @param string $filename The filename of the image/media
1124 * @return int|bool
1125 */
1126 private function get_media_id_by_name($filename) {
1127 global $wpdb;
1128 $media_id = $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid LIKE '%s'", '%'.$filename));
1129
1130 return $media_id ?: false;
1131 }
1132
1133 /**
1134 * Prepares the image for attachment and attaches it to the post object
1135 *
1136 * @param array $item A data array containing the featured image information
1137 * @param WP_Post $post The WP_Post object to where the featured image is to be attached
1138 *
1139 * @return array
1140 */
1141 private function attach_media_to_post($item, $post) {
1142
1143 // Nothing to do if "featured_media" and "featured_media_url" are both empty, thus, we bail.
1144 $featured_media = (int) $item['featured_media'];
1145 if (empty($featured_media) && empty($item['featured_media_url'])) return $item;
1146
1147 // Attach remote media if non-existing. If 'featured_media' is empty or zero
1148 // and the 'feature_media_url' is non-empty meaning we haven't gotten any local media reference just yet.
1149 // Thus, we're going to attach the remote media to this current post so that the editors can consume
1150 // and display the image to the users.
1151 if (empty($featured_media) && !empty($item['featured_media_url'])) {
1152 $media_id = $this->maybe_download_remote_image($item['featured_media_url']);
1153 if (!empty($media_id)) {
1154 $item['featured_media'] = (int) $media_id;
1155 }
1156 } else {
1157 // Check if featured media (image) still exists, meaning, not deleted/removed.
1158 if (!empty($featured_media)) {
1159 $attachment = wp_get_attachment_image_src($featured_media);
1160 if (empty($attachment)) {
1161 $item['featured_media'] = 0;
1162
1163 // Try downloading the image, if the remote page/post currently has
1164 // a featured_media_url set.
1165 if (!empty($item['featured_media_url'])) {
1166 $media_id = $this->maybe_download_remote_image($item['featured_media_url']);
1167 if (!empty($media_id)) {
1168 $item['featured_media'] = (int) $media_id;
1169 }
1170 }
1171 }
1172 }
1173 }
1174
1175 if (!empty($item['featured_media']) && $post) {
1176 set_post_thumbnail($post, (int) $item['featured_media']);
1177 }
1178
1179 return $item;
1180 }
1181
1182 /**
1183 * Saves or downloads the media (attachment/image) from UpdraftCentral
1184 *
1185 * @param string $image_url The URL of the image to download (if needed)
1186 * @param string $image_data The image data to save. If empty, image_url will be used to download the image
1187 * @return int
1188 */
1189 private function maybe_download_remote_image($image_url, $image_data = '') {
1190 if (empty($image_url)) return false;
1191
1192 $image = pathinfo($image_url);
1193 $image_name = $image['basename'];
1194
1195 $media_id = $this->get_media_id_by_name($image_name);
1196 if (!empty($media_id)) {
1197 return $media_id;
1198 }
1199
1200 $upload_dir = wp_upload_dir();
1201 if (empty($image_data)) {
1202 $response = wp_remote_get($image_url);
1203 if (!is_wp_error($response)) {
1204 $image_data = wp_remote_retrieve_body($response);
1205 }
1206 } else {
1207 $image_data = base64_decode($image_data);
1208 }
1209
1210 $media_id = 0;
1211 if (!empty($image_data)) {
1212 $filename = $image_name;
1213
1214 if (wp_mkdir_p($upload_dir['path'])) {
1215 $file = trailingslashit($upload_dir['path']).$filename;
1216 $guid = trailingslashit($upload_dir['url']).$filename;
1217 } else {
1218 $file = trailingslashit($upload_dir['basedir']).$filename;
1219 $guid = trailingslashit($upload_dir['baseurl']).$filename;
1220 }
1221
1222 file_put_contents($file, $image_data);
1223 $wp_filetype = wp_check_filetype($filename, null);
1224
1225 $attachment = array(
1226 'guid' => $guid,
1227 'post_mime_type' => $wp_filetype['type'],
1228 'post_title' => sanitize_file_name($filename),
1229 'post_content' => '',
1230 'post_status' => 'inherit'
1231 );
1232
1233 $media_id = wp_insert_attachment($attachment, $file);
1234 include_once(ABSPATH . 'wp-admin/includes/image.php');
1235
1236 $attach_data = wp_generate_attachment_metadata($media_id, $file);
1237 wp_update_attachment_metadata($media_id, $attach_data);
1238 }
1239
1240 return $media_id;
1241 }
1242
1243 /**
1244 * Gathers post categories metabox information to be rendered
1245 * in the client later on using the Handlerbarsjs templating system
1246 *
1247 * @param WP_Post $post Post object
1248 */
1249 public function post_categories_meta_box($post) {
1250 global $uc_categories_meta_box, $site_id;
1251
1252 $site_meta = $this->get_site_meta_instance();
1253 $preloaded_data = $site_meta->get_site_meta($site_id, 'updraftcentral_editor_preloaded_data_'.$post->post_type, true);
1254 $options = $misc = array();
1255
1256 if (!empty($preloaded_data)) {
1257 if (isset($preloaded_data['categories'])) {
1258 $options = $preloaded_data['categories']['misc'];
1259 }
1260
1261 if (isset($preloaded_data['post_data'])) {
1262 $misc = $preloaded_data['post_data']['misc'];
1263 }
1264 }
1265
1266 if (empty($options) || empty($misc)) return;
1267
1268 $taxonomy = json_decode($options['tax']);
1269 $popular_terms_checklist = $options['popular'];
1270 $terms_checklist = $misc['categories_checklist'];
1271 $parent_dropdown = $options['parent_dropdown'];
1272
1273 // We're pulling and rendering the template in the client, so, we're
1274 // preparing the information for the template's consumption.
1275 $uc_categories_meta_box = array(
1276 'labels' => array(
1277 'all_items' => isset($taxonomy->labels->all_items) ? $taxonomy->labels->all_items : __('All Categories', 'updraftcentral'),
1278 'most_used' => isset($taxonomy->labels->most_used) ? esc_html($taxonomy->labels->most_used) : __('Most Used', 'updraftcentral'),
1279 'add_new_item' => isset($taxonomy->labels->add_new_item) ? $taxonomy->labels->add_new_item : __('Add New Category', 'updraftcentral')
1280 ),
1281 'attributes' => array(
1282 'new_item_name' => isset($taxonomy->labels->new_item_name) ? esc_attr($taxonomy->labels->new_item_name) : __('New Category Name', 'updraftcentral'),
1283 'add_new_item' => isset($taxonomy->labels->add_new_item) ? esc_attr($taxonomy->labels->add_new_item) : __('Add New Category', 'updraftcentral')
1284 ),
1285 'can_edit_terms' => (bool) $options['capabilities']['can_edit_terms'],
1286 'popular_terms_checklist' => $popular_terms_checklist,
1287 'terms_checklist' => $terms_checklist,
1288 'parent_dropdown' => $parent_dropdown
1289 );
1290 }
1291
1292 /**
1293 * Gathers post tags metabox information to be rendered
1294 * in the client later on using the Handlerbarsjs templating system
1295 *
1296 * @param WP_Post $post Post object
1297 */
1298 public function post_tags_meta_box($post) {
1299 global $uc_tags_meta_box, $site_id;
1300
1301 $site_meta = $this->get_site_meta_instance();
1302 $preloaded_data = $site_meta->get_site_meta($site_id, 'updraftcentral_editor_preloaded_data_'.$post->post_type, true);
1303 $options = $misc = array();
1304
1305 if (!empty($preloaded_data)) {
1306 if (isset($preloaded_data['tags'])) {
1307 $options = $preloaded_data['tags']['misc'];
1308 }
1309
1310 if (isset($preloaded_data['post_data'])) {
1311 $misc = $preloaded_data['post_data']['misc'];
1312 }
1313 }
1314
1315 if (empty($options) || empty($misc)) return;
1316
1317 $tag_cloud = $options['tag_cloud'];
1318 $taxonomy = json_decode($options['tax']);
1319
1320 $terms_list = array();
1321 $terms_to_edit = '';
1322 if (!empty($misc['tags_list'])) {
1323 $terms_to_edit = str_replace(', ', ',', $misc['tags_list']);
1324 $terms_list = explode(',', $terms_to_edit);
1325 }
1326
1327 // We're pulling and rendering the template in the client, so, we're
1328 // preparing the information for the template's consumption.
1329 $uc_tags_meta_box = array(
1330 'labels' => array(
1331 'add_or_remove_items' => isset($taxonomy->labels->add_or_remove_items) ? $taxonomy->labels->add_or_remove_items : __('Add or remove tags', 'updraftcentral'),
1332 'add_new_item' => isset($taxonomy->labels->add_new_item) ? $taxonomy->labels->add_new_item : __('Add New Tag', 'updraftcentral'),
1333 'separate_items_with_commas' => isset($taxonomy->labels->separate_items_with_commas) ? $taxonomy->labels->separate_items_with_commas : __('Separate tags with commas', 'updraftcentral'),
1334 'no_terms' => isset($taxonomy->labels->no_terms) ? $taxonomy->labels->no_terms : __('No tags', 'updraftcentral'),
1335 'choose_from_most_used' => isset($taxonomy->labels->choose_from_most_used) ? $taxonomy->labels->choose_from_most_used : __('Choose from the most used tags', 'updraftcentral')
1336 ),
1337 'attributes' => array(
1338 'add' => __('Add', 'updraftcentral'),
1339 ),
1340 'can_assign_terms' => (bool) $options['capabilities']['can_assign_terms'],
1341 'terms_to_edit' => $terms_to_edit,
1342 'terms_list' => $terms_list,
1343 'tag_cloud' => $tag_cloud
1344 );
1345 }
1346 }
1347
1348 endif;
1349