public static function callback_transition_post_status($new, $old, $post) { if (in_array($post->post_type, self::get_ignored_post_types())) { return; } if (in_array($new, array('auto-draft', 'inherit'))) { return; } elseif ($old == 'auto-draft' && $new == 'draft') { $message = _x('"%1$s" %2$s drafted', '1: Post title, 2: Post type singular name', 'mainwp_child_reports'); $action = 'created'; } elseif ($old == 'auto-draft' && in_array($new, array('publish', 'private'))) { $message = _x('"%1$s" %2$s published', '1: Post title, 2: Post type singular name', 'mainwp_child_reports'); $action = 'created'; } elseif ($old == 'draft' && in_array($new, array('publish', 'private'))) { $message = _x('"%1$s" %2$s published', '1: Post title, 2: Post type singular name', 'mainwp_child_reports'); } elseif ($old == 'publish' && in_array($new, array('draft'))) { $message = _x('"%1$s" %2$s unpublished', '1: Post title, 2: Post type singular name', 'mainwp_child_reports'); } elseif ($new == 'trash') { $message = _x('"%1$s" %2$s trashed', '1: Post title, 2: Post type singular name', 'mainwp_child_reports'); $action = 'trashed'; } elseif ($old == 'trash' && $new != 'trash') { $message = _x('"%1$s" %2$s restored from trash', '1: Post title, 2: Post type singular name', 'mainwp_child_reports'); $action = 'untrashed'; } else { $message = _x('"%1$s" %2$s updated', '1: Post title, 2: Post type singular name', 'mainwp_child_reports'); } if (empty($action)) { $action = 'updated'; } $revision_id = null; if (wp_revisions_enabled($post)) { $revision = get_children(array('post_type' => 'revision', 'post_status' => 'inherit', 'post_parent' => $post->ID, 'posts_per_page' => 1, 'order' => 'desc', 'fields' => 'ids')); if ($revision) { $revision_id = $revision[0]; } } $post_type_name = strtolower(self::get_post_type_name($post->post_type)); self::log($message, array('post_title' => $post->post_title, 'singular_name' => $post_type_name, 'new_status' => $new, 'old_status' => $old, 'revision_id' => $revision_id), $post->ID, array($post->post_type => $action)); }
/** * Prepare revisions for JavaScript. * * @since 3.6.0 * * @param object $post The post object. * @param int $selected_revision_id The selected revision id. * @param int $from (optional) The revision id to compare from. * * @return array An associative array of revision data and related settings. */ function wp_prepare_revisions_for_js($post, $selected_revision_id, $from = null) { $post = get_post($post); $revisions = $authors = array(); $now_gmt = time(); $revisions = wp_get_post_revisions($post->ID, array('order' => 'ASC', 'check_enabled' => false)); // If revisions are disabled, we only want autosaves and the current post. if (!wp_revisions_enabled($post)) { foreach ($revisions as $revision_id => $revision) { if (!wp_is_post_autosave($revision)) { unset($revisions[$revision_id]); } } $revisions = array($post->ID => $post) + $revisions; } $show_avatars = get_option('show_avatars'); cache_users(wp_list_pluck($revisions, 'post_author')); $can_restore = current_user_can('edit_post', $post->ID); foreach ($revisions as $revision) { $modified = strtotime($revision->post_modified); $modified_gmt = strtotime($revision->post_modified_gmt); if ($can_restore) { $restore_link = str_replace('&', '&', wp_nonce_url(add_query_arg(array('revision' => $revision->ID, 'action' => 'restore'), admin_url('revision.php')), "restore-post_{$revision->ID}")); } if (!isset($authors[$revision->post_author])) { $authors[$revision->post_author] = array('id' => (int) $revision->post_author, 'avatar' => $show_avatars ? get_avatar($revision->post_author, 32) : '', 'name' => get_the_author_meta('display_name', $revision->post_author)); } $autosave = (bool) wp_is_post_autosave($revision); $current = !$autosave && $revision->post_modified_gmt === $post->post_modified_gmt; if ($current && !empty($current_id)) { // If multiple revisions have the same post_modified_gmt, highest ID is current. if ($current_id < $revision->ID) { $revisions[$current_id]['current'] = false; $current_id = $revision->ID; } else { $current = false; } } elseif ($current) { $current_id = $revision->ID; } $revisions[$revision->ID] = array('id' => $revision->ID, 'title' => get_the_title($post->ID), 'author' => $authors[$revision->post_author], 'date' => date_i18n(__('M j, Y @ G:i'), $modified), 'dateShort' => date_i18n(_x('j M @ G:i', 'revision date short format'), $modified), 'timeAgo' => sprintf(__('%s ago'), human_time_diff($modified_gmt, $now_gmt)), 'autosave' => $autosave, 'current' => $current, 'restoreUrl' => $can_restore ? $restore_link : false); } // If a post has been saved since the last revision (no revisioned fields were changed) // we may not have a "current" revision. Mark the latest revision as "current". if (empty($current_id)) { if ($revisions[$revision->ID]['autosave']) { $revision = end($revisions); while ($revision['autosave']) { $revision = prev($revisions); } $current_id = $revision['id']; } else { $current_id = $revision->ID; } $revisions[$current_id]['current'] = true; } // Now, grab the initial diff $compare_two_mode = is_numeric($from); if (!$compare_two_mode) { $found = array_search($selected_revision_id, array_keys($revisions)); if ($found) { $from = array_keys(array_slice($revisions, $found - 1, 1, true)); $from = reset($from); } else { $from = 0; } } $from = absint($from); $diffs = array(array('id' => $from . ':' . $selected_revision_id, 'fields' => wp_get_revision_ui_diff($post->ID, $from, $selected_revision_id))); return array('postId' => $post->ID, 'nonce' => wp_create_nonce('revisions-ajax-nonce'), 'revisionData' => array_values($revisions), 'to' => $selected_revision_id, 'from' => $from, 'diffData' => $diffs, 'baseUrl' => parse_url(admin_url('revision.php'), PHP_URL_PATH), 'compareTwoMode' => absint($compare_two_mode), 'revisionIds' => array_keys($revisions)); }
/** * Restore a post revision * * @since 3.5.0 * * @uses wp_restore_post_revision() * * @param array $args Method parameters. Contains: * - int $blog_id (unused) * - string $username * - string $password * - int $post_id * @return bool|IXR_Error false if there was an error restoring, true if success. */ public function wp_restoreRevision($args) { if (!$this->minimum_args($args, 3)) { return $this->error; } $this->escape($args); $username = $args[1]; $password = $args[2]; $revision_id = (int) $args[3]; if (!($user = $this->login($username, $password))) { return $this->error; } /** This action is documented in wp-includes/class-wp-xmlrpc-server.php */ do_action('xmlrpc_call', 'wp.restoreRevision'); if (!($revision = wp_get_post_revision($revision_id))) { return new IXR_Error(404, __('Invalid post ID')); } if (wp_is_post_autosave($revision)) { return new IXR_Error(404, __('Invalid post ID')); } if (!($post = get_post($revision->post_parent))) { return new IXR_Error(404, __('Invalid post ID')); } if (!current_user_can('edit_post', $revision->post_parent)) { return new IXR_Error(401, __('Sorry, you cannot edit this post.')); } // Check if revisions are disabled. if (!wp_revisions_enabled($post)) { return new IXR_Error(401, __('Sorry, revisions are disabled.')); } $post = wp_restore_post_revision($revision_id); return (bool) $post; }
/** * Returns all revisions of specified post. * * @since 2.6.0 * * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post. * @return array An array of revisions, or an empty array if none. */ function wp_get_post_revisions($post_id = 0, $args = null) { $post = get_post($post_id); if (!$post || empty($post->ID)) { return array(); } $defaults = array('order' => 'DESC', 'orderby' => 'date ID', 'check_enabled' => true); $args = wp_parse_args($args, $defaults); if ($args['check_enabled'] && !wp_revisions_enabled($post)) { return array(); } $args = array_merge($args, array('post_parent' => $post->ID, 'post_type' => 'revision', 'post_status' => 'inherit')); if (!($revisions = get_children($args))) { return array(); } return $revisions; }
$redirect = add_query_arg(array('message' => 5, 'revision' => $revision->ID), get_edit_post_link($post->ID, 'url')); break; case 'view': case 'edit': default: if (!($revision = wp_get_post_revision($revision_id))) { break; } if (!($post = get_post($revision->post_parent))) { break; } if (!current_user_can('read_post', $revision->ID) || !current_user_can('read_post', $post->ID)) { break; } // Revisions disabled and we're not looking at an autosave if (!wp_revisions_enabled($post) && !wp_is_post_autosave($revision)) { $redirect = 'edit.php?post_type=' . $post->post_type; break; } $post_title = '<a href="' . get_edit_post_link() . '">' . _draft_or_post_title() . '</a>'; $h2 = sprintf(__('Compare Revisions of “%1$s”'), $post_title); $title = __('Revisions'); $redirect = false; break; } // Empty post_type means either malformed object found, or no valid parent was found. if (!$redirect && empty($post->post_type)) { $redirect = 'edit.php'; } if (!empty($redirect)) { wp_redirect($redirect);
/** * Log all post status changes ( creating / updating / trashing ) * * @action transition_post_status * * @param mixed $new * @param mixed $old * @param \WP_Post $post */ public function callback_transition_post_status($new, $old, $post) { if (in_array($post->post_type, $this->get_excluded_post_types())) { return; } if (in_array($new, array('auto-draft', 'inherit'))) { return; } elseif (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } elseif ('draft' === $new && 'publish' === $old) { $summary = _x('"%1$s" %2$s unpublished', '1: Post title, 2: Post type singular name', 'stream'); } elseif ('trash' === $old && 'trash' !== $new) { $summary = _x('"%1$s" %2$s restored from trash', '1: Post title, 2: Post type singular name', 'stream'); $action = 'untrashed'; } elseif ('draft' === $new && 'draft' === $old) { $summary = _x('"%1$s" %2$s draft saved', '1: Post title, 2: Post type singular name', 'stream'); } elseif ('draft' === $new) { $summary = _x('"%1$s" %2$s drafted', '1: Post title, 2: Post type singular name', 'stream'); } elseif ('pending' === $new) { $summary = _x('"%1$s" %2$s pending review', '1: Post title, 2: Post type singular name', 'stream'); } elseif ('future' === $new) { $summary = _x('"%1$s" %2$s scheduled for %3$s', '1: Post title, 2: Post type singular name, 3: Scheduled post date', 'stream'); } elseif ('future' === $old && 'publish' === $new) { $summary = _x('"%1$s" scheduled %2$s published', '1: Post title, 2: Post type singular name', 'stream'); } elseif ('publish' === $new) { $summary = _x('"%1$s" %2$s published', '1: Post title, 2: Post type singular name', 'stream'); } elseif ('private' === $new) { $summary = _x('"%1$s" %2$s privately published', '1: Post title, 2: Post type singular name', 'stream'); } elseif ('trash' === $new) { $summary = _x('"%1$s" %2$s trashed', '1: Post title, 2: Post type singular name', 'stream'); $action = 'trashed'; } else { $summary = _x('"%1$s" %2$s updated', '1: Post title, 2: Post type singular name', 'stream'); } if ('auto-draft' === $old && 'auto-draft' !== $new) { $action = 'created'; } if (empty($action)) { $action = 'updated'; } $revision_id = null; if (wp_revisions_enabled($post)) { $revision = get_children(array('post_type' => 'revision', 'post_status' => 'inherit', 'post_parent' => $post->ID, 'posts_per_page' => 1, 'orderby' => 'post_date', 'order' => 'DESC')); if ($revision) { $revision = array_values($revision); $revision_id = $revision[0]->ID; } } $post_type_name = strtolower($this->get_post_type_name($post->post_type)); $this->log($summary, array('post_title' => $post->post_title, 'singular_name' => $post_type_name, 'post_date' => $post->post_date, 'post_date_gmt' => $post->post_date_gmt, 'new_status' => $new, 'old_status' => $old, 'revision_id' => $revision_id), $post->ID, $post->post_type, $action); }
/** * Prepare revisions for JavaScript. * * @since 3.6.0 * * @param object|int $post The post object. Also accepts a post ID. * @param int $selected_revision_id The selected revision ID. * @param int $from Optional. The revision ID to compare from. * * @return array An associative array of revision data and related settings. */ function wp_prepare_revisions_for_js($post, $selected_revision_id, $from = null) { $post = get_post($post); $authors = array(); $now_gmt = time(); $revisions = wp_get_post_revisions($post->ID, array('order' => 'ASC', 'check_enabled' => false)); // If revisions are disabled, we only want autosaves and the current post. if (!wp_revisions_enabled($post)) { foreach ($revisions as $revision_id => $revision) { if (!wp_is_post_autosave($revision)) { unset($revisions[$revision_id]); } } $revisions = array($post->ID => $post) + $revisions; } $show_avatars = get_option('show_avatars'); cache_users(wp_list_pluck($revisions, 'post_author')); $can_restore = current_user_can('edit_post', $post->ID); $current_id = false; foreach ($revisions as $revision) { $modified = strtotime($revision->post_modified); $modified_gmt = strtotime($revision->post_modified_gmt); if ($can_restore) { $restore_link = str_replace('&', '&', wp_nonce_url(add_query_arg(array('revision' => $revision->ID, 'action' => 'restore'), admin_url('revision.php')), "restore-post_{$revision->ID}")); } if (!isset($authors[$revision->post_author])) { $authors[$revision->post_author] = array('id' => (int) $revision->post_author, 'avatar' => $show_avatars ? get_avatar($revision->post_author, 32) : '', 'name' => get_the_author_meta('display_name', $revision->post_author)); } $autosave = (bool) wp_is_post_autosave($revision); $current = !$autosave && $revision->post_modified_gmt === $post->post_modified_gmt; if ($current && !empty($current_id)) { // If multiple revisions have the same post_modified_gmt, highest ID is current. if ($current_id < $revision->ID) { $revisions[$current_id]['current'] = false; $current_id = $revision->ID; } else { $current = false; } } elseif ($current) { $current_id = $revision->ID; } $revisions_data = array('id' => $revision->ID, 'title' => get_the_title($post->ID), 'author' => $authors[$revision->post_author], 'date' => date_i18n(__('M j, Y @ H:i'), $modified), 'dateShort' => date_i18n(_x('j M @ H:i', 'revision date short format'), $modified), 'timeAgo' => sprintf(__('%s ago'), human_time_diff($modified_gmt, $now_gmt)), 'autosave' => $autosave, 'current' => $current, 'restoreUrl' => $can_restore ? $restore_link : false); /** * Filter the array of revisions used on the revisions screen. * * @since 4.4.0 * * @param array $revisions_data { * The bootstrapped data for the revisions screen. * * @type int $id Revision ID. * @type string $title Title for the revision's parent WP_Post object. * @type int $author Revision post author ID. * @type string $date Date the revision was modified. * @type string $dateShort Short-form version of the date the revision was modified. * @type string $timeAgo GMT-aware amount of time ago the revision was modified. * @type bool $autosave Whether the revision is an autosave. * @type bool $current Whether the revision is both not an autosave and the post * modified date matches the revision modified date (GMT-aware). * @type bool|false $restoreUrl URL if the revision can be restored, false otherwise. * } * @param WP_Post $revision The revision's WP_Post object. * @param WP_Post $post The revision's parent WP_Post object. */ $revisions[$revision->ID] = apply_filters('wp_prepare_revision_for_js', $revisions_data, $revision, $post); } /** * If we only have one revision, the initial revision is missing; This happens * when we have an autsosave and the user has clicked 'View the Autosave' */ if (1 === sizeof($revisions)) { $revisions[$post->ID] = array('id' => $post->ID, 'title' => get_the_title($post->ID), 'author' => $authors[$post->post_author], 'date' => date_i18n(__('M j, Y @ H:i'), strtotime($post->post_modified)), 'dateShort' => date_i18n(_x('j M @ H:i', 'revision date short format'), strtotime($post->post_modified)), 'timeAgo' => sprintf(__('%s ago'), human_time_diff(strtotime($post->post_modified_gmt), $now_gmt)), 'autosave' => false, 'current' => true, 'restoreUrl' => false); $current_id = $post->ID; } /* * If a post has been saved since the last revision (no revisioned fields * were changed), we may not have a "current" revision. Mark the latest * revision as "current". */ if (empty($current_id)) { if ($revisions[$revision->ID]['autosave']) { $revision = end($revisions); while ($revision['autosave']) { $revision = prev($revisions); } $current_id = $revision['id']; } else { $current_id = $revision->ID; } $revisions[$current_id]['current'] = true; } // Now, grab the initial diff. $compare_two_mode = is_numeric($from); if (!$compare_two_mode) { $found = array_search($selected_revision_id, array_keys($revisions)); if ($found) { $from = array_keys(array_slice($revisions, $found - 1, 1, true)); $from = reset($from); } else { $from = 0; } } $from = absint($from); $diffs = array(array('id' => $from . ':' . $selected_revision_id, 'fields' => wp_get_revision_ui_diff($post->ID, $from, $selected_revision_id))); return array('postId' => $post->ID, 'nonce' => wp_create_nonce('revisions-ajax-nonce'), 'revisionData' => array_values($revisions), 'to' => $selected_revision_id, 'from' => $from, 'diffData' => $diffs, 'baseUrl' => parse_url(admin_url('revision.php'), PHP_URL_PATH), 'compareTwoMode' => absint($compare_two_mode), 'revisionIds' => array_keys($revisions)); }
/** * Determines what the user is trying to do on this page view. * * This determination is made mostly on the basis of the information passed in the URL * parameters. This function is also responsible for some of the object setup (getting the * revision post(s), etc). * * This is cribbed nearly wholesale from wp-admin/revision.php. In the future I would like * to clean it up to be less WordPressy and more pluginish. * * @package BuddyPress Docs * @since 1.1 */ function setup_action() { global $bp; if (!bp_docs_is_existing_doc()) { return; } wp_enqueue_script('list-revisions'); $redirect = false; switch ($this->action) { case 'restore': if (!($this->revision = wp_get_post_revision($this->revision_id))) { break; } if (!current_user_can('bp_docs_edit')) { break; } if (!($post = get_post($this->revision->post_parent))) { break; } // Revisions disabled and we're not looking at an autosave if (!wp_revisions_enabled($post) && !wp_is_post_autosave($this->revision)) { $redirect = 'edit.php?post_type=' . $post->post_type; break; } $referer = 'restore-post_' . $post->ID . '|' . $this->revision->ID; check_admin_referer($referer); wp_restore_post_revision($this->revision->ID); bp_core_add_message(sprintf(__('You have successfully restored the Doc to the revision from %s.', 'bp-docs'), $this->revision->post_date)); $redirect = get_permalink($post->ID) . '/' . BP_DOCS_HISTORY_SLUG . '/'; break; case 'diff': if (!($this->left_revision = get_post($this->left))) { break; } if (!($this->right_revision = get_post($this->right))) { break; } // Don't allow reverse diffs? if (strtotime($this->right_revision->post_modified_gmt) < strtotime($this->left_revision->post_modified_gmt)) { $redirect = add_query_arg(array('left' => $this->right, 'right' => $this->left)); break; } if ($this->left_revision->ID == $this->right_revision->post_parent) { // right is a revision of left $post =& $this->left_revision; } elseif ($this->left_revision->post_parent == $this->right_revision->ID) { // left is a revision of right $post =& $this->right_revision; } elseif ($this->left_revision->post_parent == $this->right_revision->post_parent) { // both are revisions of common parent $post = get_post($this->left_revision->post_parent); } else { break; } // Don't diff two unrelated revisions if (!wp_revisions_enabled($post)) { // Revisions disabled if (!wp_is_post_autosave($this->left_revision) && !wp_is_post_autosave($this->right_revision) || $post->ID !== $this->left_revision->ID && $post->ID !== $this->right_revision->ID) { $redirect = 'edit.php?post_type=' . $post->post_type; break; } } if ($this->left_revision->ID == $this->right_revision->ID || !wp_get_post_revision($this->left_revision->ID) && !wp_get_post_revision($this->right_revision->ID)) { break; } $post_title = '<a href="' . get_edit_post_link() . '">' . get_the_title() . '</a>'; $h2 = sprintf(__('Compare Revisions of “%1$s”', 'bp-docs'), $post_title); $title = __('Revisions', 'bp-docs'); $this->left = $this->left_revision->ID; $this->right = $this->right_revision->ID; $redirect = false; break; case 'view': default: if (!($this->revision = wp_get_post_revision($this->revision_id))) { if ($this->revision = get_post($this->revision_id)) { $this->is_latest = true; } else { break; } } if (!($post = get_post($this->revision->post_parent))) { break; } // Revisions disabled and we're not looking at an autosave if (!wp_revisions_enabled($post) && !wp_is_post_autosave($this->revision)) { $redirect = 'edit.php?post_type=' . $post->post_type; break; } $post_title = '<a href="' . get_edit_post_link() . '">' . get_the_title() . '</a>'; $revision_title = wp_post_revision_title($this->revision, false); $h2 = sprintf(__('Revision for “%1$s” created on %2$s', 'bp-docs'), $post_title, $revision_title); $title = __('Revisions', 'bp-docs'); // Sets up the diff radio buttons $this->left = $this->revision->ID; $this->right = $post->ID; $redirect = false; break; } if ($redirect) { bp_core_redirect($redirect); } $this->setup_is_identical(); }
/** * Publish a snapshot's changes. * * @param string $new_status New post status. * @param string $old_status Old post status. * @param WP_Post $changeset_post Changeset post object. */ function _wp_customize_publish_changeset($new_status, $old_status, $changeset_post) { global $wp_customize, $wpdb; $is_publishing_changeset = 'customize_changeset' === $changeset_post->post_type && 'publish' === $new_status && 'publish' !== $old_status; if (!$is_publishing_changeset) { return; } if (empty($wp_customize)) { require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; $wp_customize = new WP_Customize_Manager(array('changeset_uuid' => $changeset_post->post_name)); } if (!did_action('customize_register')) { /* * When running from CLI or Cron, the customize_register action will need * to be triggered in order for core, themes, and plugins to register their * settings. Normally core will add_action( 'customize_register' ) at * priority 10 to register the core settings, and if any themes/plugins * also add_action( 'customize_register' ) at the same priority, they * will have a $wp_customize with those settings registered since they * call add_action() afterward, normally. However, when manually doing * the customize_register action after the setup_theme, then the order * will be reversed for two actions added at priority 10, resulting in * the core settings no longer being available as expected to themes/plugins. * So the following manually calls the method that registers the core * settings up front before doing the action. */ remove_action('customize_register', array($wp_customize, 'register_controls')); $wp_customize->register_controls(); /** This filter is documented in /wp-includes/class-wp-customize-manager.php */ do_action('customize_register', $wp_customize); } $wp_customize->_publish_changeset_values($changeset_post->ID); /* * Trash the changeset post if revisions are not enabled. Unpublished * changesets by default get garbage collected due to the auto-draft status. * When a changeset post is published, however, it would no longer get cleaned * out. Ths is a problem when the changeset posts are never displayed anywhere, * since they would just be endlessly piling up. So here we use the revisions * feature to indicate whether or not a published changeset should get trashed * and thus garbage collected. */ if (!wp_revisions_enabled($changeset_post)) { $post = $changeset_post; $post_id = $changeset_post->ID; /* * The following re-formulates the logic from wp_trash_post() as done in * wp_publish_post(). The reason for bypassing wp_trash_post() is that it * will mutate the the post_content and the post_name when they should be * untouched. */ if (!EMPTY_TRASH_DAYS) { wp_delete_post($post_id, true); } else { /** This action is documented in wp-includes/post.php */ do_action('wp_trash_post', $post_id); add_post_meta($post_id, '_wp_trash_meta_status', $post->post_status); add_post_meta($post_id, '_wp_trash_meta_time', time()); $old_status = $post->post_status; $new_status = 'trash'; $wpdb->update($wpdb->posts, array('post_status' => $new_status), array('ID' => $post->ID)); clean_post_cache($post->ID); $post->post_status = $new_status; wp_transition_post_status($new_status, $old_status, $post); /** This action is documented in wp-includes/post.php */ do_action('edit_post', $post->ID, $post); /** This action is documented in wp-includes/post.php */ do_action("save_post_{$post->post_type}", $post->ID, $post, true); /** This action is documented in wp-includes/post.php */ do_action('save_post', $post->ID, $post, true); /** This action is documented in wp-includes/post.php */ do_action('wp_insert_post', $post->ID, $post, true); /** This action is documented in wp-includes/post.php */ do_action('trashed_post', $post_id); } } }
/** * Test WP_Customize_Manager::save_changeset_post(). * * @ticket 30937 * @covers WP_Customize_Manager::save_changeset_post() */ function test_save_changeset_post_without_theme_activation() { global $wp_customize; wp_set_current_user(self::$admin_user_id); $did_action = array('customize_save_validation_before' => did_action('customize_save_validation_before'), 'customize_save' => did_action('customize_save'), 'customize_save_after' => did_action('customize_save_after')); $uuid = wp_generate_uuid4(); $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); $wp_customize = $manager; $manager->register_controls(); $manager->set_post_value('blogname', 'Changeset Title'); $manager->set_post_value('blogdescription', 'Changeset Tagline'); $pre_saved_data = array('blogname' => array('value' => 'Overridden Changeset Title'), 'blogdescription' => array('custom' => 'something')); $date = gmdate('Y') + 1 . '-12-01 00:00:00'; $r = $manager->save_changeset_post(array('status' => 'auto-draft', 'title' => 'Auto Draft', 'date_gmt' => $date, 'data' => $pre_saved_data)); $this->assertInternalType('array', $r); $this->assertEquals($did_action['customize_save_validation_before'] + 1, did_action('customize_save_validation_before')); $post_id = $manager->find_changeset_post_id($uuid); $this->assertNotNull($post_id); $saved_data = json_decode(get_post($post_id)->post_content, true); $this->assertEquals($manager->unsanitized_post_values(), wp_list_pluck($saved_data, 'value')); $this->assertEquals($pre_saved_data['blogname']['value'], $saved_data['blogname']['value']); $this->assertEquals($pre_saved_data['blogdescription']['custom'], $saved_data['blogdescription']['custom']); foreach ($saved_data as $setting_id => $setting_params) { $this->assertArrayHasKey('type', $setting_params); $this->assertEquals('option', $setting_params['type']); $this->assertArrayHasKey('user_id', $setting_params); $this->assertEquals(self::$admin_user_id, $setting_params['user_id']); } $this->assertEquals('Auto Draft', get_post($post_id)->post_title); $this->assertEquals('auto-draft', get_post($post_id)->post_status); $this->assertEquals($date, get_post($post_id)->post_date_gmt); $this->assertNotEquals('Changeset Title', get_option('blogname')); $this->assertArrayHasKey('setting_validities', $r); // Test saving with invalid settings, ensuring transaction blocked. $previous_saved_data = $saved_data; $manager->add_setting('foo_unauthorized', array('capability' => 'do_not_allow')); $manager->add_setting('baz_illegal', array('validate_callback' => array($this, 'return_illegal_error'))); $r = $manager->save_changeset_post(array('status' => 'auto-draft', 'data' => array('blogname' => array('value' => 'OK'), 'foo_unauthorized' => array('value' => 'No'), 'bar_unknown' => array('value' => 'No'), 'baz_illegal' => array('value' => 'No')))); $this->assertInstanceOf('WP_Error', $r); $this->assertEquals('transaction_fail', $r->get_error_code()); $this->assertInternalType('array', $r->get_error_data()); $this->assertArrayHasKey('setting_validities', $r->get_error_data()); $error_data = $r->get_error_data(); $this->assertArrayHasKey('blogname', $error_data['setting_validities']); $this->assertTrue($error_data['setting_validities']['blogname']); $this->assertArrayHasKey('foo_unauthorized', $error_data['setting_validities']); $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['foo_unauthorized']); $this->assertEquals('unauthorized', $error_data['setting_validities']['foo_unauthorized']->get_error_code()); $this->assertArrayHasKey('bar_unknown', $error_data['setting_validities']); $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['bar_unknown']); $this->assertEquals('unrecognized', $error_data['setting_validities']['bar_unknown']->get_error_code()); $this->assertArrayHasKey('baz_illegal', $error_data['setting_validities']); $this->assertInstanceOf('WP_Error', $error_data['setting_validities']['baz_illegal']); $this->assertEquals('illegal', $error_data['setting_validities']['baz_illegal']->get_error_code()); // Since transactional, ensure no changes have been made. $this->assertEquals($previous_saved_data, json_decode(get_post($post_id)->post_content, true)); // Attempt a non-transactional/incremental update. $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); $wp_customize = $manager; $manager->register_controls(); // That is, register settings. $r = $manager->save_changeset_post(array('status' => null, 'data' => array('blogname' => array('value' => 'Non-Transactional \\o/ <script>unsanitized</script>'), 'bar_unknown' => array('value' => 'No')))); $this->assertInternalType('array', $r); $this->assertArrayHasKey('setting_validities', $r); $this->assertTrue($r['setting_validities']['blogname']); $this->assertInstanceOf('WP_Error', $r['setting_validities']['bar_unknown']); $saved_data = json_decode(get_post($post_id)->post_content, true); $this->assertNotEquals($previous_saved_data, $saved_data); $this->assertEquals('Non-Transactional \\o/ <script>unsanitized</script>', $saved_data['blogname']['value']); // Ensure the filter applies. $customize_changeset_save_data_call_count = $this->customize_changeset_save_data_call_count; add_filter('customize_changeset_save_data', array($this, 'filter_customize_changeset_save_data'), 10, 2); $manager->save_changeset_post(array('status' => null, 'data' => array('blogname' => array('value' => 'Filtered')))); $this->assertEquals($customize_changeset_save_data_call_count + 1, $this->customize_changeset_save_data_call_count); // Publish the changeset: actions will be doubled since also trashed. $expected_actions = array('wp_trash_post' => 1, 'clean_post_cache' => 2, 'transition_post_status' => 2, 'publish_to_trash' => 1, 'trash_customize_changeset' => 1, 'edit_post' => 2, 'save_post_customize_changeset' => 2, 'save_post' => 2, 'wp_insert_post' => 2, 'trashed_post' => 1); $action_counts = array(); foreach (array_keys($expected_actions) as $action_name) { $action_counts[$action_name] = did_action($action_name); } $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); do_action('customize_register', $wp_customize); $manager->add_setting('scratchpad', array('type' => 'option', 'capability' => 'exist')); $manager->get_setting('blogname')->capability = 'exist'; $original_capabilities = wp_list_pluck($manager->settings(), 'capability'); wp_set_current_user(self::$subscriber_user_id); $r = $manager->save_changeset_post(array('status' => 'publish', 'data' => array('blogname' => array('value' => 'Do it live \\o/'), 'scratchpad' => array('value' => '<script>console.info( "HELLO" )</script>')))); $this->assertInternalType('array', $r); $this->assertEquals('Do it live \\o/', get_option('blogname')); $this->assertEquals('trash', get_post_status($post_id)); // Auto-trashed. $this->assertEquals($original_capabilities, wp_list_pluck($manager->settings(), 'capability')); $this->assertContains('<script>', get_post($post_id)->post_content); $this->assertEquals($manager->changeset_uuid(), get_post($post_id)->post_name, 'Expected that the "__trashed" suffix to not be added.'); wp_set_current_user(self::$admin_user_id); $this->assertEquals('publish', get_post_meta($post_id, '_wp_trash_meta_status', true)); $this->assertTrue(is_numeric(get_post_meta($post_id, '_wp_trash_meta_time', true))); foreach (array_keys($expected_actions) as $action_name) { $this->assertEquals($expected_actions[$action_name] + $action_counts[$action_name], did_action($action_name), "Action: {$action_name}"); } // Test revisions. add_post_type_support('customize_changeset', 'revisions'); $uuid = wp_generate_uuid4(); $wp_customize = $manager = new WP_Customize_Manager(array('changeset_uuid' => $uuid)); do_action('customize_register', $manager); $manager->set_post_value('blogname', 'Hello Surface'); $manager->save_changeset_post(array('status' => 'auto-draft')); $manager->set_post_value('blogname', 'Hello World'); $manager->save_changeset_post(array('status' => 'draft')); $this->assertTrue(wp_revisions_enabled(get_post($manager->changeset_post_id()))); $manager->set_post_value('blogname', 'Hello Solar System'); $manager->save_changeset_post(array('status' => 'draft')); $manager->set_post_value('blogname', 'Hello Galaxy'); $manager->save_changeset_post(array('status' => 'draft')); $this->assertCount(3, wp_get_post_revisions($manager->changeset_post_id())); }
/** * Map our caps to WP's * * @since 1.2 * * @param array $caps Capabilities for meta capability * @param string $cap Capability name * @param int $user_id User id * @param mixed $args Arguments passed to map_meta_cap filter * @return array Actual capabilities for meta capability */ function bp_docs_map_meta_caps($caps, $cap, $user_id, $args) { global $post, $wp_post_types; // No need to continue if BuddyPress Docs hasn't been initialized $pt = bp_docs_get_post_type_name(); if (empty($pt)) { return $caps; } switch ($cap) { case 'bp_docs_create': // Reset all caps. We bake from scratch $caps = array(); // Should never get here if there's no user if (!$user_id) { $caps[] = 'do_not_allow'; // All logged-in users can create } else { $caps[] = 'exist'; } break; case 'bp_docs_read': case 'bp_docs_edit': case 'bp_docs_view_history': case 'bp_docs_manage': case 'bp_docs_read_comments': case 'bp_docs_post_comments': // Reset all caps. We bake from scratch $caps = array(); $doc = bp_docs_get_doc_for_caps($args); if (empty($doc)) { break; } // Special case: view_history requires post revisions // @todo Move this to addon-history if ('bp_docs_view_history' === $cap && !wp_revisions_enabled($doc)) { return array('do_not_allow'); } // Admins can do everything if (user_can($user_id, 'bp_moderate')) { return array('exist'); } $doc_settings = bp_docs_get_doc_settings($doc->ID); // Caps are stored without the 'bp_docs_' prefix, // mostly for legacy reasons $cap_name = substr($cap, 8); switch ($doc_settings[$cap_name]) { case 'anyone': $caps[] = 'exist'; break; case 'loggedin': if (!$user_id) { $caps[] = 'do_not_allow'; } else { $caps[] = 'exist'; } break; case 'creator': if ($user_id == $doc->post_author) { $caps[] = 'exist'; } else { $caps[] = 'do_not_allow'; } break; case 'no-one': default: $caps[] = 'do_not_allow'; break; // Group-specific caps get passed to filter } break; } return apply_filters('bp_docs_map_meta_caps', $caps, $cap, $user_id, $args); }
function lasso_editor_controls() { global $post; if (lasso_user_can('edit_posts')) { $status = get_post_status(get_the_ID()); // let users add custom css classes $custom_classes = apply_filters('lasso_control_classes', ''); $post_access_class = ''; $post_new_disabled = lasso_editor_get_option('post_adding_disabled', 'lasso_editor'); $post_settings_disabled = lasso_editor_get_option('post_settings_disabled', 'lasso_editor'); $shortcodify_disabled = lasso_editor_get_option('shortcodify_disabled', 'lasso_editor'); // CSS class if adding new post objects is disabled if ('on' == $post_new_disabled) { $post_access_class = 'lasso--post-new-disabled'; } // CSS class if adjust settings is disabled if ('on' == $post_settings_disabled) { $post_access_class = 'lasso--post-settings-disabled'; } // CSS class if adding new post objects AND settings are disabled if ('on' == $post_new_disabled && 'on' == $post_settings_disabled) { $post_access_class = 'lasso--post-all-disabled'; } // CSS class if shortcodify or (Aesop Shortcode Conversion) is disabled $sc_saving_class = 'on' == $shortcodify_disabled ? 'shortcodify-disabled' : 'shortcodify-enabled'; // user is capable $is_capable = is_singular() && lasso_user_can(); ?> <div id="lasso--controls" class="lasso-post-status--<?php echo sanitize_html_class($status); ?> <?php echo sanitize_html_class($custom_classes); ?> " data-post-id="<?php echo get_the_ID(); ?> " > <ul class="lasso--controls__center lasso-editor-controls lasso-editor-controls--wrap <?php echo $post_access_class; ?> "> <?php do_action('lasso_editor_controls_before'); if ($is_capable) { ?> <li id="lasso--edit" title="<?php esc_attr_e('Edit Post', 'lasso'); ?> "><a href="#" class="lasso--button__primary"></a></li> <?php if ('off' == $post_settings_disabled || empty($post_settings_disabled)) { ?> <li id="lasso--post-settings" title="<?php esc_attr_e('Post Settings', 'lasso'); ?> "><a href="#" class="lasso--button__primary"></a></li> <?php } } ?> <li id="lasso--post-all" title="<?php esc_attr_e('All Posts', 'lasso'); ?> "><a href="#" class="lasso--button__primary"></a></li> <?php if ($is_capable && wp_revisions_enabled($post)) { ?> <li id="lasso--post-revisions" title="<?php esc_attr_e('Revisions', 'lasso'); ?> "><a href="#" class="lasso--button__primary"></a></li> <?php } ?> <?php if ('off' == $post_new_disabled || empty($post_new_disabled) && lasso_user_can('publish_posts')) { ?> <li id="lasso--post-new" title="<?php esc_attr_e('Add Post', 'lasso'); ?> "><a href="#" class="lasso--button__primary"></a></li> <?php } ?> <?php do_action('lasso_editor_controls_after'); ?> </ul> <?php if (is_singular()) { ?> <div class="lasso--controls__right"> <a href="#" title="<?php esc_attr_e('Save Post', 'lasso'); ?> " id="lasso--save" class="lasso-save-post lasso--button <?php echo $sc_saving_class; ?> "></a> <?php if ('draft' == $status && (lasso_user_can('publish_posts') || lasso_user_can('publish_pages'))) { ?> <a href="#" title="<?php esc_attr_e('Publish Post', 'lasso'); ?> " id="lasso--publish" class="lasso-publish-post lasso--button <?php echo $sc_saving_class; ?> "></a> <?php } ?> </div> <?php } ?> </div> <?php } }
/** * Checks if revisions are enabled, post has more than one revision and the type of current post is visible in REST. * * @since 1.0.0 * @access public * * @return bool|string If revisions for current entry aren't available, returns false. Otherwise a string for REST endpoint base. */ public function get_available_base_rest() { static $rest_base; if (!isset($rest_base)) { $post = get_post(); if ($post instanceof WP_Post && wp_revisions_enabled($post) && 1 < count(wp_get_post_revisions())) { $post_type = get_post_type_object(get_post_type($post)); $rest_base = isset($post_type->show_in_rest) && $post_type->show_in_rest ? $post_type->rest_base : false; } else { $rest_base = false; } } return $rest_base; }