public function save()
{
if (!is_user_logged_in()) {
wp_send_json_error('unauthenticated');
}
if (!$this->is_preview()) {
wp_send_json_error('not_preview');
}
$action = 'save-customize_' . $this->get_stylesheet();
if (!check_ajax_referer($action, 'nonce', false)) {
wp_send_json_error('invalid_nonce');
}
$changeset_post_id = $this->changeset_post_id();
if ($changeset_post_id && in_array(get_post_status($changeset_post_id), array('publish', 'trash'))) {
wp_send_json_error('changeset_already_published');
}
if (empty($changeset_post_id)) {
if (!current_user_can(get_post_type_object('customize_changeset')->cap->create_posts)) {
wp_send_json_error('cannot_create_changeset_post');
}
} else {
if (!current_user_can(get_post_type_object('customize_changeset')->cap->edit_post, $changeset_post_id)) {
wp_send_json_error('cannot_edit_changeset_post');
}
}
if (!empty($_POST['customize_changeset_data'])) {
$input_changeset_data = json_decode(wp_unslash($_POST['customize_changeset_data']), true);
if (!is_array($input_changeset_data)) {
wp_send_json_error('invalid_customize_changeset_data');
}
} else {
$input_changeset_data = array();
}
// Validate title.
$changeset_title = null;
if (isset($_POST['customize_changeset_title'])) {
$changeset_title = sanitize_text_field(wp_unslash($_POST['customize_changeset_title']));
}
// Validate changeset status param.
$is_publish = null;
$changeset_status = null;
if (isset($_POST['customize_changeset_status'])) {
$changeset_status = wp_unslash($_POST['customize_changeset_status']);
if (!get_post_status_object($changeset_status) || !in_array($changeset_status, array('draft', 'pending', 'publish', 'future'), true)) {
wp_send_json_error('bad_customize_changeset_status', 400);
}
$is_publish = 'publish' === $changeset_status || 'future' === $changeset_status;
if ($is_publish) {
if (!current_user_can(get_post_type_object('customize_changeset')->cap->publish_posts)) {
wp_send_json_error('changeset_publish_unauthorized', 403);
}
if (false === has_action('transition_post_status', '_wp_customize_publish_changeset')) {
wp_send_json_error('missing_publish_callback', 500);
}
}
}
/*
* Validate changeset date param. Date is assumed to be in local time for
* the WP if in MySQL format (YYYY-MM-DD HH:MM:SS). Otherwise, the date
* is parsed with strtotime() so that ISO date format may be supplied
* or a string like "+10 minutes".
*/
$changeset_date_gmt = null;
if (isset($_POST['customize_changeset_date'])) {
$changeset_date = wp_unslash($_POST['customize_changeset_date']);
if (preg_match('/^\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d$/', $changeset_date)) {
$mm = substr($changeset_date, 5, 2);
$jj = substr($changeset_date, 8, 2);
$aa = substr($changeset_date, 0, 4);
$valid_date = wp_checkdate($mm, $jj, $aa, $changeset_date);
if (!$valid_date) {
wp_send_json_error('bad_customize_changeset_date', 400);
}
$changeset_date_gmt = get_gmt_from_date($changeset_date);
} else {
$timestamp = strtotime($changeset_date);
if (!$timestamp) {
wp_send_json_error('bad_customize_changeset_date', 400);
}
$changeset_date_gmt = gmdate('Y-m-d H:i:s', $timestamp);
}
$now = gmdate('Y-m-d H:i:59');
$is_future_dated = mysql2date('U', $changeset_date_gmt, false) > mysql2date('U', $now, false);
if (!$is_future_dated) {
wp_send_json_error('not_future_date', 400);
// Only future dates are allowed.
}
if (!$this->is_theme_active() && ('future' === $changeset_status || $is_future_dated)) {
wp_send_json_error('cannot_schedule_theme_switches', 400);
// This should be allowed in the future, when theme is a regular setting.
}
$will_remain_auto_draft = !$changeset_status && (!$changeset_post_id || 'auto-draft' === get_post_status($changeset_post_id));
if ($changeset_date && $will_remain_auto_draft) {
wp_send_json_error('cannot_supply_date_for_auto_draft_changeset', 400);
}
}
$r = $this->save_changeset_post(array('status' => $changeset_status, 'title' => $changeset_title, 'date_gmt' => $changeset_date_gmt, 'data' => $input_changeset_data));
if (is_wp_error($r)) {
$response = $r->get_error_data();
} else {
$response = $r;
// Note that if the changeset status was publish, then it will get set to trash if revisions are not supported.
$response['changeset_status'] = get_post_status($this->changeset_post_id());
if ($is_publish && 'trash' === $response['changeset_status']) {
$response['changeset_status'] = 'publish';
}
if ('publish' === $response['changeset_status']) {
$response['next_changeset_uuid'] = wp_generate_uuid4();
}
}
if (isset($response['setting_validities'])) {
$response['setting_validities'] = array_map(array($this, 'prepare_setting_validity_for_js'), $response['setting_validities']);
}
/**
* Filters response data for a successful customize_save Ajax request.
*
* This filter does not apply if there was a nonce or authentication failure.
*
* @since 4.2.0
*
* @param array $response Additional information passed back to the 'saved'
* event on `wp.customize`.
* @param WP_Customize_Manager $this WP_Customize_Manager instance.
*/
$response = apply_filters('customize_save_response', $response, $this);
if (is_wp_error($r)) {
wp_send_json_error($response);
} else {
wp_send_json_success($response);
}
}