Ticket #25272: 25272.3.patch
File 25272.3.patch, 49.1 KB (added by , 11 years ago) |
---|
-
src/wp-admin/admin-ajax.php
49 49 'oembed-cache', 'image-editor', 'delete-comment', 'delete-tag', 'delete-link', 50 50 'delete-meta', 'delete-post', 'trash-post', 'untrash-post', 'delete-page', 'dim-comment', 51 51 'add-link-category', 'add-tag', 'get-tagcloud', 'get-comments', 'replyto-comment', 52 'edit-comment', 'add-menu-item', 'add-meta', 'add-user', ' autosave', 'closed-postboxes',52 'edit-comment', 'add-menu-item', 'add-meta', 'add-user', 'closed-postboxes', 53 53 'hidden-columns', 'update-welcome-panel', 'menu-get-metabox', 'wp-link-ajax', 54 54 'menu-locations-save', 'menu-quick-search', 'meta-box-order', 'get-permalink', 55 55 'sample-permalink', 'inline-save', 'inline-save-tax', 'find_posts', 'widgets-order', -
src/wp-admin/edit-form-advanced.php
347 347 348 348 echo $form_extra; 349 349 350 wp_nonce_field( 'autosave', 'autosavenonce', false );351 350 wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); 352 351 wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); 353 352 ?> -
src/wp-admin/includes/ajax-actions.php
1057 1057 $x->send(); 1058 1058 } 1059 1059 1060 function wp_ajax_autosave() {1061 define( 'DOING_AUTOSAVE', true );1062 1063 check_ajax_referer( 'autosave', 'autosavenonce' );1064 1065 if ( ! empty( $_POST['catslist'] ) )1066 $_POST['post_category'] = explode( ',', $_POST['catslist'] );1067 if ( $_POST['post_type'] == 'page' || empty( $_POST['post_category'] ) )1068 unset( $_POST['post_category'] );1069 1070 $data = '';1071 $supplemental = array();1072 $id = $revision_id = 0;1073 1074 $post_id = (int) $_POST['post_id'];1075 $_POST['ID'] = $_POST['post_ID'] = $post_id;1076 $post = get_post( $post_id );1077 if ( empty( $post->ID ) || ! current_user_can( 'edit_post', $post->ID ) )1078 wp_die( __( 'You are not allowed to edit this post.' ) );1079 1080 if ( 'page' == $post->post_type && ! current_user_can( 'edit_page', $post->ID ) )1081 wp_die( __( 'You are not allowed to edit this page.' ) );1082 1083 if ( 'auto-draft' == $post->post_status )1084 $_POST['post_status'] = 'draft';1085 1086 if ( ! empty( $_POST['autosave'] ) ) {1087 if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) {1088 // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked1089 $id = edit_post();1090 } else {1091 // Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user.1092 $revision_id = wp_create_post_autosave( $post->ID );1093 if ( is_wp_error($revision_id) )1094 $id = $revision_id;1095 else1096 $id = $post->ID;1097 }1098 1099 if ( ! is_wp_error($id) ) {1100 /* translators: draft saved date format, see http://php.net/date */1101 $draft_saved_date_format = __('g:i:s a');1102 /* translators: %s: date and time */1103 $data = sprintf( __('Draft saved at %s.'), date_i18n( $draft_saved_date_format ) );1104 }1105 } else {1106 if ( ! empty( $_POST['auto_draft'] ) )1107 $id = 0; // This tells us it didn't actually save1108 else1109 $id = $post->ID;1110 }1111 1112 // @todo Consider exposing any errors, rather than having 'Saving draft...'1113 $x = new WP_Ajax_Response( array(1114 'what' => 'autosave',1115 'id' => $id,1116 'data' => $data,1117 'supplemental' => $supplemental1118 ) );1119 $x->send();1120 }1121 1122 1060 function wp_ajax_closed_postboxes() { 1123 1061 check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' ); 1124 1062 $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array(); -
src/wp-admin/includes/misc.php
683 683 if ( 2 === wp_verify_nonce( $received['post_nonce'], 'update-post_' . $post_id ) ) { 684 684 $response['wp-refresh-post-nonces'] = array( 685 685 'replace' => array( 686 'autosavenonce' => wp_create_nonce('autosave'),687 686 'getpermalinknonce' => wp_create_nonce('getpermalink'), 688 687 'samplepermalinknonce' => wp_create_nonce('samplepermalink'), 689 688 'closedpostboxesnonce' => wp_create_nonce('closedpostboxes'), … … 698 697 return $response; 699 698 } 700 699 add_filter( 'heartbeat_received', 'wp_refresh_post_nonces', 10, 3 ); 700 701 /** 702 * Autosave with heartbeat 703 * 704 * @since 3.7 705 */ 706 function wp_autosave( $response, $data ) { 707 if ( ! empty( $data['autosave'] ) ) { 708 $saved = autosave( $data['autosave'] ); 709 710 if ( is_wp_error( $saved ) ) { 711 $response['autosave'] = array( 'success' => false, 'message' => $saved->get_error_message() ); 712 } elseif ( empty( $saved ) ) { 713 $response['autosave'] = array( 'success' => false, 'message' => __( 'Error while saving the draft.' ) ); 714 } else { 715 /* translators: draft saved date format, see http://php.net/date */ 716 $draft_saved_date_format = __( 'g:i:s a' ); 717 /* translators: %s: date and time */ 718 $response['autosave'] = array( 'success' => true, 'message' => sprintf( __( 'Draft saved at %s.' ), date_i18n( $draft_saved_date_format ) ) ); 719 } 720 } 721 722 return $response; 723 } 724 // Run later as we have to set DOING_AUTOSAVE for back-compat 725 add_filter( 'heartbeat_received', 'wp_autosave', 50, 2 ); -
src/wp-admin/includes/post.php
79 79 } 80 80 } 81 81 82 if ( ! empty( $post_data['post_status'] ) ) 82 if ( ! empty( $post_data['post_status'] ) ) { 83 83 $post_data['post_status'] = sanitize_key( $post_data['post_status'] ); 84 84 85 // No longer an auto-draft 86 if ( 'auto-draft' == $post_data['post_status'] ) 87 $post_data['post_status'] = 'draft'; 88 } 89 85 90 // What to do based on which button they pressed 86 91 if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] ) 87 92 $post_data['post_status'] = 'draft'; … … 181 186 $post_data = _wp_translate_postdata( true, $post_data ); 182 187 if ( is_wp_error($post_data) ) 183 188 wp_die( $post_data->get_error_message() ); 184 if ( ( empty( $post_data['action'] ) || 'autosave' != $post_data['action'] ) && 'auto-draft' == $post_data['post_status'] ) {185 $post_data['post_status'] = 'draft';186 }187 189 188 190 if ( isset($post_data['visibility']) ) { 189 191 switch ( $post_data['visibility'] ) { … … 1321 1323 * @uses _wp_translate_postdata() 1322 1324 * @uses _wp_post_revision_fields() 1323 1325 * 1324 * @return unknown 1326 * @param mixed $post_data Associative array containing the post data or int post ID. 1327 * @return mixed The autosave revision ID. WP_Error or 0 on error. 1325 1328 */ 1326 function wp_create_post_autosave( $post_id ) { 1327 $translated = _wp_translate_postdata( true ); 1328 if ( is_wp_error( $translated ) ) 1329 return $translated; 1329 function wp_create_post_autosave( $post_data ) { 1330 if ( is_numeric( $post_data ) ) { 1331 $post_id = $post_data; 1332 $post_data = &$_POST; 1333 } else { 1334 $post_id = (int) $post_data['post_ID']; 1335 } 1330 1336 1337 $post_data = _wp_translate_postdata( true, $post_data ); 1338 if ( is_wp_error( $post_data ) ) 1339 return $post_data; 1340 1331 1341 $post_author = get_current_user_id(); 1332 1342 1333 1343 // Store one autosave per author. If there is already an autosave, overwrite it. 1334 1344 if ( $old_autosave = wp_get_post_autosave( $post_id, $post_author ) ) { 1335 $new_autosave = _wp_post_revision_fields( $ _POST, true );1345 $new_autosave = _wp_post_revision_fields( $post_data, true ); 1336 1346 $new_autosave['ID'] = $old_autosave->ID; 1337 1347 $new_autosave['post_author'] = $post_author; 1338 1348 1339 // If the new autosave is the same content as the post, delete the oldautosave.1349 // If the new autosave has the same content as the post, delete the autosave. 1340 1350 $post = get_post( $post_id ); 1341 1351 $autosave_is_different = false; 1342 1352 foreach ( array_keys( _wp_post_revision_fields() ) as $field ) { … … 1348 1358 1349 1359 if ( ! $autosave_is_different ) { 1350 1360 wp_delete_post_revision( $old_autosave->ID ); 1351 return ;1361 return 0; 1352 1362 } 1353 1363 1354 1364 return wp_update_post( $new_autosave ); … … 1355 1365 } 1356 1366 1357 1367 // _wp_put_post_revision() expects unescaped. 1358 $post_data = wp_unslash( $ _POST);1368 $post_data = wp_unslash( $post_data ); 1359 1369 1360 1370 // Otherwise create the new autosave as a special post revision 1361 1371 return _wp_put_post_revision( $post_data, true ); … … 1381 1391 function post_preview() { 1382 1392 1383 1393 $post_ID = (int) $_POST['post_ID']; 1384 $status = get_post_status( $post_ID ); 1385 if ( 'auto-draft' == $status ) 1386 wp_die( __('Preview not available. Please save as a draft first.') ); 1394 $_POST['ID'] = $post_ID; 1387 1395 1388 if ( isset($_POST['catslist']) )1389 $_POST['post_category'] = explode(",", $_POST['catslist']);1396 if ( ! $post = get_post( $post_ID ) ) 1397 wp_die( __('You attempted to preview a non existing item.') ); 1390 1398 1391 if ( isset($_POST['tags_input']) )1392 $_POST['tags_input'] = explode(",", $_POST['tags_input']);1399 if ( ! current_user_can( 'edit_post', $post->ID ) ) 1400 wp_die( __('You are not allowed to preview this item.') ); 1393 1401 1394 if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) ) 1395 unset($_POST['post_category']); 1402 $is_autosave = false; 1396 1403 1397 $_POST['ID'] = $post_ID; 1398 $post = get_post($post_ID); 1399 1400 if ( 'page' == $post->post_type ) { 1401 if ( ! current_user_can('edit_page', $post_ID) ) 1402 wp_die( __('You are not allowed to edit this page.') ); 1404 if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'draft' == $post->post_status || 'auto-draft' == $post->post_status ) ) { 1405 $saved_post_id = edit_post(); 1403 1406 } else { 1404 if ( ! current_user_can('edit_post', $post_ID) ) 1405 wp_die( __('You are not allowed to edit this post.') ); 1406 } 1407 $is_autosave = true; 1407 1408 1408 $user_id = get_current_user_id(); 1409 $locked = wp_check_post_lock( $post->ID ); 1410 if ( ! $locked && 'draft' == $post->post_status && $user_id == $post->post_author ) { 1411 $id = edit_post(); 1412 } else { // Non drafts are not overwritten. The autosave is stored in a special post revision. 1413 $id = wp_create_post_autosave( $post->ID ); 1414 if ( ! is_wp_error($id) ) 1415 $id = $post->ID; 1409 if ( 'auto-draft' == $_POST['post_status'] ) 1410 $_POST['post_status'] = 'draft'; 1411 1412 $saved_post_id = wp_create_post_autosave( $post->ID ); 1416 1413 } 1417 1414 1418 if ( is_wp_error( $id) )1419 wp_die( $ id->get_error_message() );1415 if ( is_wp_error( $saved_post_id ) ) 1416 wp_die( $saved_post_id->get_error_message() ); 1420 1417 1421 if ( ! $locked && $_POST['post_status'] == 'draft' && $user_id == $post->post_author ) { 1422 $url = add_query_arg( 'preview', 'true', get_permalink($id) ); 1423 } else { 1424 $nonce = wp_create_nonce('post_preview_' . $id); 1425 $args = array( 1426 'preview' => 'true', 1427 'preview_id' => $id, 1428 'preview_nonce' => $nonce, 1429 ); 1418 $query_args = array( 'preview' => 'true' ); 1430 1419 1420 if ( $is_autosave && $saved_post_id ) { 1421 $query_args['preview_id'] = $post->ID; 1422 $query_args['preview_nonce'] = wp_create_nonce( 'post_preview_' . $post->ID ); 1423 1431 1424 if ( isset( $_POST['post_format'] ) ) 1432 $args['post_format'] = empty( $_POST['post_format'] ) ? 'standard' : sanitize_key( $_POST['post_format'] ); 1433 1434 $url = add_query_arg( $args, get_permalink($id) ); 1425 $query_args['post_format'] = empty( $_POST['post_format'] ) ? 'standard' : sanitize_key( $_POST['post_format'] ); 1435 1426 } 1436 1427 1428 $url = add_query_arg( $query_args, get_permalink( $post->ID ) ); 1437 1429 return apply_filters( 'preview_post_link', $url ); 1438 1430 } 1431 1432 /** 1433 * Save a post submitted with XHR 1434 * 1435 * Intended for use with heartbeat and autosave.js 1436 * 1437 * @since 3.7 1438 * 1439 * @param $post_data Associative array of the submitted post data. 1440 * @return mixed The value 0 or WP_Error on failure. The saved post ID on success. 1441 * Te ID can be either the draft post_id or the autosave revision post_id. 1442 */ 1443 function autosave( $post_data ) { 1444 // Back-compat 1445 if ( ! defined( 'DOING_AUTOSAVE' ) ) 1446 define( 'DOING_AUTOSAVE', true ); 1447 1448 $post_id = (int) $post_data['post_id']; 1449 $post_data['ID'] = $post_data['post_ID'] = $post_id; 1450 1451 if ( false === wp_verify_nonce( $post_data['_wpnonce'], 'update-post_' . $post_id ) ) 1452 return new WP_Error( 'invalid_nonce', __('ERROR: invalid post data.') ); 1453 1454 $post = get_post( $post_id ); 1455 1456 if ( ! current_user_can( 'edit_post', $post->ID ) ) 1457 return new WP_Error( 'edit_post', __('You are not allowed to edit this item.') ); 1458 1459 if ( 'auto-draft' == $post->post_status ) 1460 $post_data['post_status'] = 'draft'; 1461 1462 if ( $post_data['post_type'] != 'page' && ! empty( $post_data['catslist'] ) ) 1463 $post_data['post_category'] = explode( ',', $post_data['catslist'] ); 1464 1465 if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) { 1466 // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked 1467 return edit_post( $post_data ); 1468 } else { 1469 // Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user. 1470 return wp_create_post_autosave( $post_data ); 1471 } 1472 } -
src/wp-admin/js/post.js
1 var tagBox, commentsBox, editPermalink, makeSlugeditClickable, WPSetThumbnailHTML, WPSetThumbnailID, WPRemoveThumbnail, wptitlehint; 1 var tagBox, commentsBox, WPSetThumbnailHTML, WPSetThumbnailID, WPRemoveThumbnail, wptitlehint; 2 // Prevent fatal errors (back-compat) 3 makeSlugeditClickable = editPermalink = function(){}; 2 4 3 5 // return an array with any duplicate, whitespace or values removed 4 6 function array_unique_noempty(a) { … … 265 267 send['lock'] = lock; 266 268 267 269 data['wp-refresh-post-lock'] = send; 268 });269 270 270 // Post locks: update the lock string or show the dialog if somebody has taken over editing 271 $(document).on( 'heartbeat-tick.refresh-lock', function( e, data ) { 271 }).on( 'heartbeat-tick.refresh-lock', function( e, data ) { 272 // Post locks: update the lock string or show the dialog if somebody has taken over editing 272 273 var received, wrap, avatar; 273 274 274 275 if ( data['wp-refresh-post-lock'] ) { … … 279 280 wrap = $('#post-lock-dialog'); 280 281 281 282 if ( wrap.length && ! wrap.is(':visible') ) { 282 if ( typeof autosave == 'function') {283 $(document).on('autosave-disable-buttons.post-lock', function() {284 wrap.addClass('saving');285 }).on('autosave-enable-buttons.post-lock', function() {283 if ( typeof wp != 'undefined' && wp.autosave ) { 284 // Save the latest changes and disable 285 $(document).one( 'heartbeat-tick', function() { 286 wp.autosave.server.disable(); 286 287 wrap.removeClass('saving').addClass('saved'); 287 window.onbeforeunload = null;288 $(window).off( 'beforeunload.autosave' ); 288 289 }); 289 290 290 // Save the latest changes and disable 291 if ( ! autosave() ) 292 window.onbeforeunload = null; 293 294 autosave = function(){}; 291 wrap.addClass('saving'); 292 wp.autosave.server.triggerSave(); 295 293 } 296 294 297 295 if ( received.lock_error.avatar_src ) { … … 306 304 $('#active_post_lock').val( received.new_lock ); 307 305 } 308 306 } 307 }).on( 'after-autosave.update-post-slug', function() { 308 // create slug area only if not already there 309 if ( ! $('#edit-slug-box > *').length ) { 310 $.post( ajaxurl, { 311 action: 'sample-permalink', 312 post_id: $('#post_ID').val(), 313 new_title: typeof fullscreen != 'undefined' && fullscreen.settings.visible ? $('#wp-fullscreen-title').val() : $('#title').val(), 314 samplepermalinknonce: $('#samplepermalinknonce').val() 315 }, 316 function( data ) { 317 if ( data != '-1' ) { 318 $('#edit-slug-box').html(data); 319 } 320 } 321 ); 322 } 309 323 }); 310 324 311 325 }(jQuery)); … … 351 365 }(jQuery)); 352 366 353 367 jQuery(document).ready( function($) { 354 var stamp, visibility, sticky = '', last = 0, co = $('#content'); 368 var stamp, visibility, sticky = '', last = 0, co = $('#content'), $editSlugWrap = $('#edit-slug-box'), 369 postId = $('#post_ID').val() || 0, $submitpost = $('#submitpost'), releaseLock = true; 355 370 356 371 postboxes.add_postbox_toggles(pagenow); 357 372 … … 371 386 } 372 387 }).filter(':visible').find('.wp-tab-first').focus(); 373 388 389 // The form is being submitted by the user 390 $submitpost.find( 'input[type="submit"], a.submitdelete' ).on( 'click.autosave', function( event ) { 391 var $button = $(this); 392 393 if ( $button.prop('disabled') ) { 394 event.preventDefault(); 395 return; 396 } 397 398 if ( $button.hasClass('submitdelete') ) { 399 return; 400 } 401 402 // The form submission can be blocked from JS or by using HTML 5.0 validation on some fields. 403 // Run this only on an actual 'submit'. 404 $('form#post').off( 'submit.edit-post' ).on( 'submit.edit-post', function( event ) { 405 if ( event.isDefaultPrevented() ) 406 return; 407 408 wp.autosave.server.disable(); 409 releaseLock = false; 410 $(window).off( 'beforeunload.edit-post' ); 411 412 $submitpost.find('a.submitdelete, #post-preview').addClass('button-disabled'); 413 414 if ( $button.attr('id') == 'publish' ) 415 $submitpost.find('#major-publishing-actions .spinner').show(); 416 else 417 $submitpost.find('#minor-publishing .spinner').show(); 418 }); 419 }); 420 421 // Submit the form saving a draft or an autosave, and show a preview in a new tab 422 $('#post-preview').on( 'click.post-preview', function( event ) { 423 event.preventDefault(); 424 425 if ( $(this).prop('disabled') ) { 426 return; 427 } 428 429 wp.autosave.server.blockSave(); 430 $('input#wp-preview').val('dopreview'); 431 $('form#post').attr('target', 'wp-preview').submit().attr('target', ''); 432 433 // Workaround for WebKit bug preventing a form submitting twice to the same action. 434 // https://bugs.webkit.org/show_bug.cgi?id=28633 435 var ua = navigator.userAgent.toLowerCase(); 436 if ( ua.indexOf('safari') != -1 && ua.indexOf('chrome') == -1 ) { 437 $('form#post').attr( 'action', function( index, value ) { 438 return value + '?t=' + new Date().getTime(); 439 }); 440 } 441 442 $('input#wp-preview').val(''); 443 }); 444 445 // This code is meant to allow tabbing from Title to Post content. 446 $('#title').on( 'keydown.editor-focus', function( event ) { 447 var editor; 448 449 if ( event.which == 9 && ! event.ctrlKey && ! event.altKey && ! event.shiftKey ) { 450 editor = typeof tinymce != 'undefined' && tinymce.get('content'); 451 452 if ( editor && ! editor.isHidden() ) { 453 $(this).one( 'keyup', function() { 454 $('#content_tbl td.mceToolbar > a').focus(); 455 }); 456 } else { 457 $('#content').focus(); 458 } 459 460 event.preventDefault(); 461 } 462 }); 463 464 $(window).on( 'beforeunload.edit-post', function() { 465 var editor = typeof tinymce != 'undefined' && tinymce.activeEditor, compareString; 466 467 if ( editor && ! editor.isHidden() ) { 468 if ( editor.isDirty() ) 469 return autosaveL10n.saveAlert; 470 } else { 471 if ( fullscreen && fullscreen.settings.visible ) { 472 compareString = wp.autosave.getCompareString({ 473 post_title: $('#wp-fullscreen-title').val() || '', 474 content: $('#wp_mce_fullscreen').val() || '', 475 excerpt: $('#excerpt').val() || '' 476 }); 477 } else { 478 compareString = wp.autosave.getCompareString(); 479 } 480 481 if ( compareString != wp.autosave.server.autosaveLast ) 482 return autosaveL10n.saveAlert; 483 } 484 }).on( 'unload.edit-post', function( event ) { 485 if ( ! releaseLock ) 486 return; 487 488 // Unload is triggered (by hand) on removing the Thickbox iframe. 489 // Make sure we process only the main document unload. 490 if ( event.target && event.target.nodeName != '#document' ) 491 return; 492 493 $.ajax({ 494 type: 'POST', 495 url: ajaxurl, 496 async: false, 497 data: { 498 action: 'wp-remove-post-lock', 499 _wpnonce: $('#_wpnonce').val(), 500 post_ID: $('#post_ID').val(), 501 active_post_lock: $('#active_post_lock').val() 502 } 503 }); 504 }); 505 374 506 // multi-taxonomies 375 507 if ( $('#tagsdiv-post_tag').length ) { 376 508 tagBox.init(); … … 680 812 } // end submitdiv 681 813 682 814 // permalink 683 if ( $('#edit-slug-box').length ) { 684 editPermalink = function(post_id) { 685 var i, c = 0, e = $('#editable-post-name'), revert_e = e.html(), real_slug = $('#post_name'), revert_slug = real_slug.val(), b = $('#edit-slug-buttons'), revert_b = b.html(), full = $('#editable-post-name-full').html(); 815 if ( $editSlugWrap.length ) { 816 function editPermalink() { 817 var i, c = 0, e = $('#editable-post-name'), revert_e = e.html(), real_slug = $('#post_name'), 818 revert_slug = real_slug.val(), b = $('#edit-slug-buttons'), revert_b = b.html(), 819 full = $('#editable-post-name-full').html(); 686 820 687 821 $('#view-post-btn').hide(); 688 822 b.html('<a href="#" class="save button button-small">'+postL10n.ok+'</a> <a class="cancel" href="#">'+postL10n.cancel+'</a>'); … … 689 823 b.children('.save').click(function() { 690 824 var new_slug = e.children('input').val(); 691 825 if ( new_slug == $('#editable-post-name-full').text() ) { 692 return $(' .cancel', '#edit-slug-buttons').click();826 return $('#edit-slug-buttons .cancel').click(); 693 827 } 694 828 $.post(ajaxurl, { 695 829 action: 'sample-permalink', 696 post_id: post _id,830 post_id: postId, 697 831 new_slug: new_slug, 698 832 new_title: $('#title').val(), 699 833 samplepermalinknonce: $('#samplepermalinknonce').val() … … 707 841 } 708 842 b.html(revert_b); 709 843 real_slug.val(new_slug); 710 makeSlugeditClickable();711 844 $('#view-post-btn').show(); 712 845 }); 713 846 return false; 714 847 }); 715 848 716 $(' .cancel', '#edit-slug-buttons').click(function() {849 $('#edit-slug-buttons .cancel').click(function() { 717 850 $('#view-post-btn').show(); 718 851 e.html(revert_e); 719 852 b.html(revert_b); … … 743 876 }).focus(); 744 877 } 745 878 746 makeSlugeditClickable = function() { 747 $('#editable-post-name').click(function() { 748 $('#edit-slug-buttons').children('.edit-slug').click(); 749 }); 750 } 751 makeSlugeditClickable(); 879 $editSlugWrap.on( 'click', function( event ) { 880 var $target = $( event.target ); 881 882 if ( $target.is('#editable-post-name') || $target.hasClass('edit-slug') ) { 883 editPermalink(); 884 } 885 }); 752 886 } 753 887 754 888 // word count -
src/wp-admin/post.php
296 296 break; 297 297 298 298 case 'preview': 299 check_admin_referer( ' autosave', 'autosavenonce');299 check_admin_referer( 'update-post_' . $post_id ); 300 300 301 301 $url = post_preview(); 302 302 -
src/wp-includes/js/autosave.js
1 var autosave, autosaveLast = '', autosavePeriodical, autosaveDelayPreview = false, notSaved = true, blockSave = false, fullscreen, autosaveLockRelease = true;1 window.wp = window.wp || {}; 2 2 3 jQuery(document).ready( function($) { 3 ( function( $, window ) { 4 var $document = $(document), nextRun = 0, _disabled, _blockSave, _blockSaveTimeout; 4 5 5 if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' ) { 6 autosaveLast = wp.autosave.getCompareString({ 7 post_title : $('#title').val() || '', 8 content : switchEditors.pre_wpautop( $('#content').val() ) || '', 9 excerpt : $('#excerpt').val() || '' 10 }); 11 } else{12 autosaveLast = wp.autosave.getCompareString();13 }6 /** 7 * Returns the data saved in both local and remote autosave 8 * 9 * @return mixed Object containing the post data or false 10 */ 11 wp.autosave = { 12 getPostData: function( type ) { 13 var post_name, parent_id, cats = [], data, 14 editor = typeof tinymce != 'undefined' && tinymce.get('content'); 14 15 15 autosavePeriodical = $.schedule({time: autosaveL10n.autosaveInterval * 1000, func: function() { autosave(); }, repeat: true, protect: true});16 17 //Disable autosave after the form has been submitted18 $("#post").submit(function() {19 $.cancel(autosavePeriodical);20 autosaveLockRelease = false;21 });22 23 $('input[type="submit"], a.submitdelete', '#submitpost').click(function(){24 blockSave = true;25 window.onbeforeunload = null;26 $(':button, :submit', '#submitpost').each(function(){27 var t = $(this);28 if ( t.hasClass('button-primary') )29 t.addClass('button-primary-disabled');30 else31 t.addClass('button-disabled');32 });33 if ( $(this).attr('id') == 'publish' )34 $('#major-publishing-actions .spinner').show();35 else36 $('#minor-publishing .spinner').show();37 });38 39 window.onbeforeunload = function(){40 var editor = typeof(tinymce) != 'undefined' ? tinymce.activeEditor : false, compareString;41 42 16 if ( editor && ! editor.isHidden() ) { 43 if ( editor.isDirty() ) 44 return autosaveL10n.saveAlert; 45 } else { 46 if ( fullscreen && fullscreen.settings.visible ) { 47 compareString = wp.autosave.getCompareString({ 48 post_title: $('#wp-fullscreen-title').val() || '', 49 content: $('#wp_mce_fullscreen').val() || '', 50 excerpt: $('#excerpt').val() || '' 51 }); 17 // Don't run while the tinymce spellcheck is on. It resets all found words. 18 if ( editor.plugins.spellchecker && editor.plugins.spellchecker.active ) { 19 return false; 52 20 } else { 53 compareString = wp.autosave.getCompareString();21 tinymce.triggerSave(); 54 22 } 55 56 if ( compareString != autosaveLast )57 return autosaveL10n.saveAlert;58 23 } 59 };60 24 61 $(window).unload( function(e) {62 if ( ! autosaveLockRelease )63 return;64 65 // unload fires (twice) on removing the Thickbox iframe. Make sure we process only the main document unload.66 if ( e.target && e.target.nodeName != '#document' )67 return;68 69 $.ajax({70 type: 'POST',71 url: ajaxurl,72 async: false,73 data: {74 action: 'wp-remove-post-lock',75 _wpnonce: $('#_wpnonce').val(),76 post_ID: $('#post_ID').val(),77 active_post_lock: $('#active_post_lock').val()78 }79 });80 } );81 82 // preview83 $('#post-preview').click(function(){84 if ( $('#auto_draft').val() == '1' && notSaved ) {85 autosaveDelayPreview = true;86 autosave();87 return false;88 }89 doPreview();90 return false;91 });92 93 doPreview = function() {94 $('input#wp-preview').val('dopreview');95 $('form#post').attr('target', 'wp-preview').submit().attr('target', '');96 97 /*98 * Workaround for WebKit bug preventing a form submitting twice to the same action.99 * https://bugs.webkit.org/show_bug.cgi?id=28633100 */101 var ua = navigator.userAgent.toLowerCase();102 if ( ua.indexOf('safari') != -1 && ua.indexOf('chrome') == -1 ) {103 $('form#post').attr('action', function(index, value) {104 return value + '?t=' + new Date().getTime();105 });106 }107 108 $('input#wp-preview').val('');109 }110 111 // This code is meant to allow tabbing from Title to Post content.112 $('#title').on('keydown.editor-focus', function(e) {113 var ed;114 115 if ( e.which != 9 )116 return;117 118 if ( !e.ctrlKey && !e.altKey && !e.shiftKey ) {119 if ( typeof(tinymce) != 'undefined' )120 ed = tinymce.get('content');121 122 if ( ed && !ed.isHidden() ) {123 $(this).one('keyup', function(e){124 $('#content_tbl td.mceToolbar > a').focus();125 });126 } else {127 $('#content').focus();128 }129 130 e.preventDefault();131 }132 });133 134 // autosave new posts after a title is typed but not if Publish or Save Draft is clicked135 if ( '1' == $('#auto_draft').val() ) {136 $('#title').blur( function() {137 if ( !this.value || $('#auto_draft').val() != '1' )138 return;139 delayed_autosave();140 });141 }142 143 // When connection is lost, keep user from submitting changes.144 $(document).on('heartbeat-connection-lost.autosave', function( e, error ) {145 if ( 'timeout' === error ) {146 var notice = $('#lost-connection-notice');147 if ( ! wp.autosave.local.hasStorage ) {148 notice.find('.hide-if-no-sessionstorage').hide();149 }150 notice.show();151 autosave_disable_buttons();152 }153 }).on('heartbeat-connection-restored.autosave', function() {154 $('#lost-connection-notice').hide();155 autosave_enable_buttons();156 });157 });158 159 function autosave_parse_response( response ) {160 var res = wpAjax.parseAjaxResponse(response, 'autosave'), post_id, sup;161 162 if ( res && res.responses && res.responses.length ) {163 if ( res.responses[0].supplemental ) {164 sup = res.responses[0].supplemental;165 166 jQuery.each( sup, function( selector, value ) {167 if ( selector.match(/^replace-/) )168 jQuery( '#' + selector.replace('replace-', '') ).val( value );169 });170 }171 172 // if no errors: add slug UI and update autosave-message173 if ( !res.errors ) {174 if ( post_id = parseInt( res.responses[0].id, 10 ) )175 autosave_update_slug( post_id );176 177 if ( res.responses[0].data ) // update autosave message178 jQuery('.autosave-message').text( res.responses[0].data );179 }180 }181 182 return res;183 }184 185 // called when autosaving pre-existing post186 function autosave_saved(response) {187 blockSave = false;188 autosave_parse_response(response); // parse the ajax response189 autosave_enable_buttons(); // re-enable disabled form buttons190 }191 192 // called when autosaving new post193 function autosave_saved_new(response) {194 blockSave = false;195 var res = autosave_parse_response(response), post_id;196 197 if ( res && res.responses.length && !res.errors ) {198 // An ID is sent only for real auto-saves, not for autosave=0 "keepalive" saves199 post_id = parseInt( res.responses[0].id, 10 );200 201 if ( post_id ) {202 notSaved = false;203 jQuery('#auto_draft').val('0'); // No longer an auto-draft204 }205 206 autosave_enable_buttons();207 208 if ( autosaveDelayPreview ) {209 autosaveDelayPreview = false;210 doPreview();211 }212 } else {213 autosave_enable_buttons(); // re-enable disabled form buttons214 }215 }216 217 function autosave_update_slug(post_id) {218 // create slug area only if not already there219 if ( 'undefined' != makeSlugeditClickable && jQuery.isFunction(makeSlugeditClickable) && !jQuery('#edit-slug-box > *').size() ) {220 jQuery.post( ajaxurl, {221 action: 'sample-permalink',222 post_id: post_id,223 new_title: fullscreen && fullscreen.settings.visible ? jQuery('#wp-fullscreen-title').val() : jQuery('#title').val(),224 samplepermalinknonce: jQuery('#samplepermalinknonce').val()225 },226 function(data) {227 if ( data !== '-1' ) {228 var box = jQuery('#edit-slug-box');229 box.html(data);230 if (box.hasClass('hidden')) {231 box.fadeIn('fast', function () {232 box.removeClass('hidden');233 });234 }235 makeSlugeditClickable();236 }237 }238 );239 }240 }241 242 function autosave_loading() {243 jQuery('.autosave-message').html(autosaveL10n.savingText);244 }245 246 function autosave_enable_buttons() {247 jQuery(document).trigger('autosave-enable-buttons');248 if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) {249 // delay that a bit to avoid some rare collisions while the DOM is being updated.250 setTimeout(function(){251 var parent = jQuery('#submitpost');252 parent.find(':button, :submit').removeAttr('disabled');253 parent.find('.spinner').hide();254 }, 500);255 }256 }257 258 function autosave_disable_buttons() {259 jQuery(document).trigger('autosave-disable-buttons');260 jQuery('#submitpost').find(':button, :submit').prop('disabled', true);261 // Re-enable 5 sec later. Just gives autosave a head start to avoid collisions.262 setTimeout( autosave_enable_buttons, 5000 );263 }264 265 function delayed_autosave() {266 setTimeout(function(){267 if ( blockSave )268 return;269 autosave();270 }, 200);271 }272 273 autosave = function() {274 var post_data = wp.autosave.getPostData(),275 compareString,276 successCallback;277 278 blockSave = true;279 280 // post_data.content cannot be retrieved at the moment281 if ( ! post_data.autosave )282 return false;283 284 // No autosave while thickbox is open (media buttons)285 if ( jQuery("#TB_window").css('display') == 'block' )286 return false;287 288 compareString = wp.autosave.getCompareString( post_data );289 290 // Nothing to save or no change.291 if ( compareString == autosaveLast )292 return false;293 294 autosaveLast = compareString;295 jQuery(document).triggerHandler('wpcountwords', [ post_data["content"] ]);296 297 // Disable buttons until we know the save completed.298 autosave_disable_buttons();299 300 if ( post_data["auto_draft"] == '1' ) {301 successCallback = autosave_saved_new; // new post302 } else {303 successCallback = autosave_saved; // pre-existing post304 }305 306 jQuery.ajax({307 data: post_data,308 beforeSend: autosave_loading,309 type: "POST",310 url: ajaxurl,311 success: successCallback312 });313 314 return true;315 }316 317 // Autosave in localStorage318 // set as simple object/mixin for now319 window.wp = window.wp || {};320 wp.autosave = wp.autosave || {};321 322 (function($){323 // Returns the data for saving in both localStorage and autosaves to the server324 wp.autosave.getPostData = function() {325 var ed = typeof tinymce != 'undefined' ? tinymce.activeEditor : null, post_name, parent_id, cats = [],326 25 data = { 327 action: 'autosave',328 autosave: true,329 26 post_id: $('#post_ID').val() || 0, 330 autosavenonce: $('#autosavenonce').val() || '',331 27 post_type: $('#post_type').val() || '', 332 28 post_author: $('#post_author').val() || '', 333 29 excerpt: $('#excerpt').val() || '' 334 30 }; 335 31 336 if ( ed && !ed.isHidden() ) { 337 // Don't run while the tinymce spellcheck is on. It resets all found words. 338 if ( ed.plugins.spellchecker && ed.plugins.spellchecker.active ) { 339 data.autosave = false; 340 return data; 32 if ( typeof fullscreen != 'undefined' && fullscreen.settings.visible ) { 33 data['post_title'] = $('#wp-fullscreen-title').val() || ''; 34 data['content'] = $('#wp_mce_fullscreen').val() || ''; 341 35 } else { 342 if ( 'mce_fullscreen' == ed.id ) 343 tinymce.get('content').setContent(ed.getContent({format : 'raw'}), {format : 'raw'}); 344 345 tinymce.triggerSave(); 36 data['post_title'] = $('#title').val() || ''; 37 data['content'] = $('#content').val() || ''; 346 38 } 347 }348 39 349 if ( typeof fullscreen != 'undefined' && fullscreen.settings.visible ) { 350 data['post_title'] = $('#wp-fullscreen-title').val() || ''; 351 data['content'] = $('#wp_mce_fullscreen').val() || ''; 352 } else { 353 data['post_title'] = $('#title').val() || ''; 354 data['content'] = $('#content').val() || ''; 355 } 40 if ( type == 'local' ) 41 return data; 356 42 357 /* 358 // We haven't been saving tags with autosave since 2.8... Start again? 359 $('.the-tags').each( function() { 360 data[this.name] = this.value; 361 }); 362 */ 43 $('input[id^="in-category-"]:checked').each( function() { 44 cats.push( this.value ); 45 }); 46 data['catslist'] = cats.join(','); 363 47 364 $('input[id^="in-category-"]:checked').each( function() { 365 cats.push(this.value); 366 }); 367 data['catslist'] = cats.join(','); 48 if ( post_name = $('#post_name').val() ) 49 data['post_name'] = post_name; 368 50 369 if ( post_name = $('#post_name').val() )370 data['post_name'] = post_name;51 if ( parent_id = $('#parent_id').val() ) 52 data['parent_id'] = parent_id; 371 53 372 if ( parent_id = $('#parent_id').val() )373 data['parent_id'] = parent_id;54 if ( $('#comment_status').prop('checked') ) 55 data['comment_status'] = 'open'; 374 56 375 if ( $('#comment_status').prop('checked') )376 data['comment_status'] = 'open';57 if ( $('#ping_status').prop('checked') ) 58 data['ping_status'] = 'open'; 377 59 378 if ( $('#ping_status').prop('checked'))379 data['ping_status'] = 'open';60 if ( $('#auto_draft').val() == '1' ) 61 data['auto_draft'] = '1'; 380 62 381 if ( $('#auto_draft').val() == '1' )382 data['auto_draft'] = '1';63 return data; 64 }, 383 65 384 return data; 385 }; 66 // Concatenate title, content and excerpt. Used to track changes when auto-saving. 67 getCompareString: function( post_data ) { 68 if ( typeof post_data === 'object' ) { 69 return ( post_data.post_title || '' ) + '::' + ( post_data.content || '' ) + '::' + ( post_data.excerpt || '' ); 70 } 386 71 387 // Concatenate title, content and excerpt. Used to track changes when auto-saving. 388 wp.autosave.getCompareString = function( post_data ) { 389 if ( typeof post_data === 'object' ) { 390 return ( post_data.post_title || '' ) + '::' + ( post_data.content || '' ) + '::' + ( post_data.excerpt || '' ); 72 return ( $('#title').val() || '' ) + '::' + ( $('#content').val() || '' ) + '::' + ( $('#excerpt').val() || '' ); 73 }, 74 75 enableButtons: function() { 76 $document.trigger('autosave-enable-buttons'); 77 78 if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) { 79 $('#submitpost').find(':button, :submit, a.submitdelete, #post-preview').prop( 'disabled', false ).removeClass( 'button-disabled' ); 80 } 81 }, 82 83 disableButtons: function() { 84 $document.trigger('autosave-disable-buttons'); 85 $('#submitpost').find(':button, :submit, a.submitdelete, #post-preview').prop( 'disabled', true ).addClass( 'button-disabled' ); 86 // Re-enable 5 sec later. Just gives autosave a head start to avoid collisions. 87 setTimeout( wp.autosave.enableButtons, 5000 ); 391 88 } 392 393 return ( $('#title').val() || '' ) + '::' + ( $('#content').val() || '' ) + '::' + ( $('#excerpt').val() || '' );394 89 }; 395 90 91 // Autosave in localStorage 92 // set as simple object/mixin for now 396 93 wp.autosave.local = { 397 398 94 lastSavedData: '', 399 95 blog_id: 0, 400 96 hasStorage: false, … … 502 198 save: function( data ) { 503 199 var result = false, post_data, compareString; 504 200 505 if ( ! data ) { 506 post_data = wp.autosave.getPostData(); 507 } else { 201 if ( data ) { 508 202 post_data = this.getData() || {}; 509 203 $.extend( post_data, data ); 510 post_data.autosave = true; 204 } else { 205 post_data = wp.autosave.getPostData('local'); 206 // Cannot get the post data at the moment 207 if ( ! post_data ) 208 return false; 511 209 } 512 210 513 // Cannot get the post data at the moment514 if ( ! post_data.autosave )515 return false;516 517 211 compareString = wp.autosave.getCompareString( post_data ); 518 212 519 213 // If the content, title and excerpt did not change since the last save, don't save again … … 697 391 } 698 392 }; 699 393 394 // Autosave on the server 395 wp.autosave.server = { 396 autosaveLast: '', 397 398 init: function() { 399 var self = this; 400 401 $document.on( 'heartbeat-send.autosave', function( event, data ) { 402 var autosaveData = self.getData(); 403 404 if ( autosaveData ) { 405 data.autosave = autosaveData; 406 } 407 }).on( 'heartbeat-tick.autosave', function( event, data ) { 408 if ( data.autosave ) { 409 self.response( data.autosave ); 410 } 411 }).on('heartbeat-connection-lost.autosave', function( event, error ) { 412 // When connection is lost, keep user from submitting changes. 413 if ( 'timeout' === error ) { 414 var notice = $('#lost-connection-notice'); 415 416 if ( ! wp.autosave.local.hasStorage ) { 417 notice.find('.hide-if-no-sessionstorage').hide(); 418 } 419 420 notice.show(); 421 wp.autosave.disableButtons(); 422 } 423 }).on('heartbeat-connection-restored.autosave', function() { 424 $('#lost-connection-notice').hide(); 425 wp.autosave.enableButtons(); 426 }).ready( function() { 427 self._schedule(); 428 429 if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' ) { 430 self.autosaveLast = wp.autosave.getCompareString({ 431 post_title : $('#title').val() || '', 432 content : switchEditors.pre_wpautop( $('#content').val() ) || '', 433 excerpt : $('#excerpt').val() || '' 434 }); 435 } else { 436 self.autosaveLast = wp.autosave.getCompareString(); 437 } 438 439 // Autosave new posts after a title is typed 440 if ( $('#auto_draft').val() ) { 441 $('#title').blur( function() { 442 if ( ! this.value || $('#auto_draft').val() != '1' ) 443 return; 444 445 self.triggerSave(); 446 }); 447 } 448 }); 449 }, 450 451 // Block saving for the next 10 sec. 452 blockSave: function() { 453 _blockSave = true; 454 window.clearTimeout( _blockSaveTimeout ); 455 _blockSaveTimeout = window.setTimeout( function() { 456 _blockSave = false; 457 }, 10000 ); 458 }, 459 460 // Runs on heartbeat-response 461 response: function( data ) { 462 this._schedule(); 463 _blockSave = false; 464 this.autosaveLast = this.lastCompareString; 465 this.lastCompareString = ''; 466 467 $document.trigger( 'after-autosave', [data] ); 468 $('.autosave-message').text( data.message ); 469 wp.autosave.enableButtons(); 470 471 if ( data.success ) { 472 // No longer an auto-draft 473 $('#auto_draft').val(''); 474 } 475 }, 476 477 disable: function() { 478 _disabled = true; 479 }, 480 481 _schedule: function() { 482 nextRun = ( new Date() ).getTime() + ( autosaveL10n.autosaveInterval * 1000 ) || 60000; 483 }, 484 485 // Reset the timing and tell heartbeat to connect now 486 triggerSave: function() { 487 nextRun = 0; 488 wp.heartbeat.connectNow(); 489 }, 490 491 // Runs on 'heartbeat-send' 492 getData: function() { 493 var compareString, postData; 494 495 if ( _disabled || _blockSave ) { 496 return false; 497 } 498 499 if ( ( new Date() ).getTime() < nextRun ) { 500 return false; 501 } 502 503 postData = wp.autosave.getPostData(); 504 505 // post_data.content cannot be retrieved at the moment 506 if ( ! postData ) { 507 return false; 508 } 509 510 compareString = wp.autosave.getCompareString( postData ); 511 512 // Nothing to save or no change. 513 if ( compareString == this.autosaveLast ) { 514 return false; 515 } 516 517 this.blockSave(); 518 wp.autosave.disableButtons(); 519 this.lastCompareString = compareString; 520 521 $document.trigger( 'wpcountwords', [ postData['content'] ] ) 522 .trigger( 'before-autosave', [ postData ] ); 523 524 $('.autosave-message').text( autosaveL10n.savingText ); 525 postData._wpnonce = $('#_wpnonce').val() || ''; 526 527 return postData; 528 } 529 }; 530 700 531 wp.autosave.local.init(); 532 wp.autosave.server.init(); 701 533 702 }( jQuery));534 }( jQuery, window )); -
src/wp-includes/revision.php
215 215 * 216 216 * @param int|object|array $post Post ID, post object OR post array. 217 217 * @param bool $autosave Optional. Is the revision an autosave? 218 * @return mixed Nullor 0 if error, new revision ID if success.218 * @return mixed WP_Error or 0 if error, new revision ID if success. 219 219 */ 220 220 function _wp_put_post_revision( $post = null, $autosave = false ) { 221 221 if ( is_object($post) ) … … 223 223 elseif ( !is_array($post) ) 224 224 $post = get_post($post, ARRAY_A); 225 225 226 if ( ! $post || empty($post['ID']) )227 return ;226 if ( ! $post || empty($post['ID']) ) 227 return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) ); 228 228 229 229 if ( isset($post['post_type']) && 'revision' == $post['post_type'] ) 230 230 return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) ); -
tests/phpunit/includes/testcase-ajax.php
42 42 'oembed_cache', 'image-editor', 'delete-comment', 'delete-tag', 'delete-link', 43 43 'delete-meta', 'delete-post', 'trash-post', 'untrash-post', 'delete-page', 'dim-comment', 44 44 'add-link-category', 'add-tag', 'get-tagcloud', 'get-comments', 'replyto-comment', 45 'edit-comment', 'add-menu-item', 'add-meta', 'add-user', ' autosave', 'closed-postboxes',45 'edit-comment', 'add-menu-item', 'add-meta', 'add-user', 'closed-postboxes', 46 46 'hidden-columns', 'update-welcome-panel', 'menu-get-metabox', 'wp-link-ajax', 47 47 'menu-locations-save', 'menu-quick-search', 'meta-box-order', 'get-permalink', 48 48 'sample-permalink', 'inline-save', 'inline-save-tax', 'find_posts', 'widgets-order', 49 49 'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post', 50 'wp-remove-post-lock', 'dismiss-wp-pointer', ' nopriv_autosave'50 'wp-remove-post-lock', 'dismiss-wp-pointer', 'heartbeat', 'nopriv_heartbeat', 51 51 ); 52 52 53 53 /** -
tests/phpunit/tests/ajax/Autosave.php
23 23 protected $_post = null; 24 24 25 25 /** 26 * user_id 27 * @var int 28 */ 29 protected $user_id = 0; 30 31 /** 26 32 * Set up the test fixture 27 33 */ 28 34 public function setUp() { 29 35 parent::setUp(); 36 // Set a user so the $post has 'post_author' 37 $this->user_id = $this->factory->user->create( array( 'role' => 'administrator' ) ); 38 wp_set_current_user( $this->user_id ); 39 30 40 $post_id = $this->factory->post->create( array( 'post_status' => 'draft' ) ); 31 41 $this->_post = get_post( $post_id ); 32 42 } 33 43 34 44 /** 45 * Tear down the test fixture. 46 * Reset the current user 47 */ 48 public function tearDown() { 49 parent::tearDown(); 50 wp_set_current_user( 0 ); 51 } 52 53 /** 35 54 * Test autosaving a post 36 55 * @return void 37 56 */ 38 57 public function test_autosave_post() { 58 // The original post_author 59 wp_set_current_user( $this->user_id ); 39 60 40 // Become an admin41 $this->_setRole( 'administrator' );42 43 61 // Set up the $_POST request 44 62 $md5 = md5( uniqid() ); 45 63 $_POST = array( 46 'post_id' => $this->_post->ID, 47 'autosavenonce' => wp_create_nonce( 'autosave' ), 48 'post_content' => $this->_post->post_content . PHP_EOL . $md5, 49 'post_type' => 'post', 50 'autosave' => 1, 64 'action' => 'heartbeat', 65 '_nonce' => wp_create_nonce( 'heartbeat-nonce' ), 66 'data' => array( 67 'autosave' => array( 68 'post_id' => $this->_post->ID, 69 '_wpnonce' => wp_create_nonce( 'update-post_' . $this->_post->ID ), 70 'post_content' => $this->_post->post_content . PHP_EOL . $md5, 71 'post_type' => 'post', 72 ), 73 ), 51 74 ); 52 75 53 76 // Make the request 54 77 try { 55 $this->_handleAjax( ' autosave' );78 $this->_handleAjax( 'heartbeat' ); 56 79 } catch ( WPAjaxDieContinueException $e ) { 57 80 unset( $e ); 58 81 } 59 82 60 // Get the response 61 $ xml = simplexml_load_string( $this->_last_response, 'SimpleXMLElement', LIBXML_NOCDATA);83 // Get the response, it is in heartbeat's response 84 $response = json_decode( $this->_last_response, true ); 62 85 63 86 // Ensure everything is correct 64 $this->assert Equals( $this->_post->ID, (int) $xml->response[0]->autosave['id'] );65 $this->assert Equals( 'autosave_' . $this->_post->ID, (string) $xml->response['action']);87 $this->assertNotEmpty( $response['autosave'] ); 88 $this->assertTrue( $response['autosave']['success'] ); 66 89 67 90 // Check that the edit happened 68 $post = get_post( $this->_post->ID );91 $post = get_post( $this->_post->ID ); 69 92 $this->assertGreaterThanOrEqual( 0, strpos( $post->post_content, $md5 ) ); 70 93 } 71 94 72 95 /** 73 * Test with an invalid nonce96 * Test autosaving a locked post 74 97 * @return void 75 98 */ 76 public function test_with_invalid_nonce( ) { 99 public function test_autosave_locked_post() { 100 // Lock the post to another user 101 $another_user_id = $this->factory->user->create( array( 'role' => 'editor' ) ); 102 wp_set_current_user( $another_user_id ); 103 wp_set_post_lock( $this->_post->ID ); 104 105 wp_set_current_user( $this->user_id ); 77 106 78 // Become an administrator79 $this-> _setRole( 'administrator');107 // Ensure post is locked 108 $this->assertEquals( $another_user_id, wp_check_post_lock( $this->_post->ID ) ); 80 109 81 110 // Set up the $_POST request 111 $md5 = md5( uniqid() ); 82 112 $_POST = array( 83 'post_id' => $this->_post->ID, 84 'autosavenonce' => md5( uniqid() ), 85 'autosave' => 1 113 'action' => 'heartbeat', 114 '_nonce' => wp_create_nonce( 'heartbeat-nonce' ), 115 'data' => array( 116 'autosave' => array( 117 'post_id' => $this->_post->ID, 118 '_wpnonce' => wp_create_nonce( 'update-post_' . $this->_post->ID ), 119 'post_content' => $this->_post->post_content . PHP_EOL . $md5, 120 'post_type' => 'post', 121 ), 122 ), 86 123 ); 87 124 88 125 // Make the request 89 $this->setExpectedException( 'WPAjaxDieStopException', '-1' ); 90 $this->_handleAjax( 'autosave' ); 126 try { 127 $this->_handleAjax( 'heartbeat' ); 128 } catch ( WPAjaxDieContinueException $e ) { 129 unset( $e ); 130 } 131 132 $response = json_decode( $this->_last_response, true ); 133 134 // Ensure everything is correct 135 $this->assertNotEmpty( $response['autosave'] ); 136 $this->assertTrue( $response['autosave']['success'] ); 137 138 // Check that the original post was NOT edited 139 $post = get_post( $this->_post->ID ); 140 $this->assertFalse( strpos( $post->post_content, $md5 ) ); 141 142 // Check if the autosave post was created 143 $autosave = wp_get_post_autosave( $this->_post->ID, get_current_user_id() ); 144 $this->assertNotEmpty( $autosave ); 145 $this->assertGreaterThanOrEqual( 0, strpos( $autosave->post_content, $md5 ) ); 91 146 } 92 147 93 148 /** 94 * Test with a bad post id149 * Test with an invalid nonce 95 150 * @return void 96 151 */ 97 public function test_with_invalid_ post_id( ) {152 public function test_with_invalid_nonce( ) { 98 153 99 // Become an administrator 100 $this->_setRole( 'administrator' ); 154 wp_set_current_user( $this->user_id ); 101 155 102 156 // Set up the $_POST request 103 157 $_POST = array( 104 'post_id' => 0, 105 'autosavenonce' => wp_create_nonce( 'autosave' ), 106 'autosave' => 1, 107 'post_type' => 'post' 158 'action' => 'heartbeat', 159 '_nonce' => wp_create_nonce( 'heartbeat-nonce' ), 160 'data' => array( 161 'autosave' => array( 162 'post_id' => $this->_post->ID, 163 '_wpnonce' => substr( md5( uniqid() ), 0, 10 ), 164 ), 165 ), 108 166 ); 109 167 110 168 // Make the request 111 $this->setExpectedException( 'WPAjaxDieStopException', 'You are not allowed to edit this post.' ); 112 $this->_handleAjax( 'autosave' ); 169 try { 170 $this->_handleAjax( 'heartbeat' ); 171 } catch ( WPAjaxDieContinueException $e ) { 172 unset( $e ); 173 } 174 175 $response = json_decode( $this->_last_response, true ); 176 177 $this->assertNotEmpty( $response['autosave'] ); 178 $this->assertFalse( $response['autosave']['success'] ); 113 179 } 114 180 }