Changeset 62338
- Timestamp:
- 05/08/2026 03:58:51 PM (8 hours ago)
- Location:
- branches/7.0
- Files:
-
- 4 deleted
- 17 edited
-
. (modified) (1 prop)
-
src/js/_enqueues/admin/inline-edit-post.js (modified) (2 diffs)
-
src/wp-admin/css/list-tables.css (modified) (1 diff)
-
src/wp-admin/includes/class-wp-posts-list-table.php (modified) (3 diffs)
-
src/wp-admin/includes/misc.php (modified) (2 diffs)
-
src/wp-admin/includes/schema.php (modified) (1 diff)
-
src/wp-admin/options-writing.php (modified) (1 diff)
-
src/wp-admin/options.php (modified) (1 diff)
-
src/wp-includes/collaboration (deleted)
-
src/wp-includes/collaboration.php (deleted)
-
src/wp-includes/default-filters.php (modified) (1 diff)
-
src/wp-includes/option.php (modified) (1 diff)
-
src/wp-includes/post.php (modified) (3 diffs)
-
src/wp-includes/rest-api.php (modified) (1 diff)
-
src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php (modified) (2 diffs)
-
src/wp-settings.php (modified) (1 diff)
-
tests/phpunit/tests/collaboration (deleted)
-
tests/phpunit/tests/rest-api/rest-autosaves-controller.php (modified) (3 diffs)
-
tests/phpunit/tests/rest-api/rest-settings-controller.php (modified) (1 diff)
-
tests/phpunit/tests/rest-api/rest-sync-server.php (deleted)
-
tests/qunit/fixtures/wp-api-generated.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/7.0
- Property svn:mergeinfo changed
/trunk merged: 62334,62337
- Property svn:mergeinfo changed
-
branches/7.0/src/js/_enqueues/admin/inline-edit-post.js
r62074 r62338 615 615 }).on( 'heartbeat-tick.wp-check-locked-posts', function( e, data ) { 616 616 var locked = data['wp-check-locked-posts'] || {}, 617 isRtc = window._wpCollaborationEnabled, 618 lockedClass = isRtc ? 'wp-collaborative-editing' : 'wp-locked'; 617 lockedClass = 'wp-locked'; 619 618 620 619 $('#the-list tr').each( function(i, el) { … … 627 626 row.find('.check-column checkbox').prop('checked', false); 628 627 629 if ( ! isRtc &&lock_data.avatar_src ) {628 if ( lock_data.avatar_src ) { 630 629 avatar = $( '<img />', { 631 630 'class': 'avatar avatar-18 photo', -
branches/7.0/src/wp-admin/css/list-tables.css
r62307 r62338 636 636 } 637 637 638 .wp-collaborative-editing .locked-info {639 display: block;640 }641 642 .join-action-text {643 display: none;644 }645 646 .wp-collaborative-editing .edit-action-text {647 display: none;648 }649 650 .wp-collaborative-editing .join-action-text {651 display: inline;652 }653 654 638 #menu-locations-wrap .widefat { 655 639 width: 60%; -
branches/7.0/src/wp-admin/includes/class-wp-posts-list-table.php
r62215 r62338 1120 1120 1121 1121 if ( $lock_holder ) { 1122 if ( get_option( 'wp_collaboration_enabled' ) ) { 1123 $locked_avatar = ''; 1124 /* translators: Collaboration status message for a singular post in the post list. Can be any type of post. */ 1125 $locked_text = esc_html_x( 'Currently being edited', 'post list' ); 1126 } else { 1127 $lock_holder = get_userdata( $lock_holder ); 1128 $locked_avatar = get_avatar( $lock_holder->ID, 18 ); 1129 /* translators: %s: User's display name. */ 1130 $locked_text = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) ); 1131 } 1122 $lock_holder = get_userdata( $lock_holder ); 1123 $locked_avatar = get_avatar( $lock_holder->ID, 18 ); 1124 /* translators: %s: User's display name. */ 1125 $locked_text = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) ); 1132 1126 } else { 1133 1127 $locked_avatar = ''; … … 1434 1428 1435 1429 if ( $lock_holder ) { 1436 if ( get_option( 'wp_collaboration_enabled' ) ) { 1437 $classes .= ' wp-collaborative-editing'; 1438 } else { 1439 $classes .= ' wp-locked'; 1440 } 1430 $classes .= ' wp-locked'; 1441 1431 } 1442 1432 … … 1492 1482 1493 1483 if ( $can_edit_post && 'trash' !== $post->post_status ) { 1494 $is_rtc_enabled = (bool) get_option( 'wp_collaboration_enabled' ); 1495 1496 /* 1497 * When RTC is enabled, both "Edit" and "Join" labels are rendered. 1498 * The visible label is toggled by CSS based on the row's 1499 * `wp-collaborative-editing` class, which is added or removed by 1500 * inline-edit-post.js in response to heartbeat ticks. 1501 */ 1502 if ( $is_rtc_enabled ) { 1503 $actions['edit'] = sprintf( 1504 '<a href="%1$s">' 1505 . '<span class="edit-action-text">' 1506 . '<span aria-hidden="true">%2$s</span>' 1507 . '<span class="screen-reader-text">%3$s</span>' 1508 . '</span>' 1509 . '<span class="join-action-text">' 1510 . '<span aria-hidden="true">%4$s</span>' 1511 . '<span class="screen-reader-text">%5$s</span>' 1512 . '</span>' 1513 . '</a>', 1514 get_edit_post_link( $post->ID ), 1515 __( 'Edit' ), 1516 /* translators: %s: Post title. */ 1517 sprintf( __( 'Edit “%s”' ), $title ), 1518 /* translators: Action link text for a singular post in the post list. Can be any type of post. */ 1519 _x( 'Join', 'post list' ), 1520 /* translators: %s: Post title. */ 1521 sprintf( __( 'Join editing “%s”', 'post list' ), $title ) 1522 ); 1523 } else { 1524 $actions['edit'] = sprintf( 1525 '<a href="%s" aria-label="%s">%s</a>', 1526 get_edit_post_link( $post->ID ), 1527 /* translators: %s: Post title. */ 1528 esc_attr( sprintf( __( 'Edit “%s”' ), $title ) ), 1529 __( 'Edit' ) 1530 ); 1531 } 1484 $actions['edit'] = sprintf( 1485 '<a href="%s" aria-label="%s">%s</a>', 1486 get_edit_post_link( $post->ID ), 1487 /* translators: %s: Post title. */ 1488 esc_attr( sprintf( __( 'Edit “%s”' ), $title ) ), 1489 __( 'Edit' ) 1490 ); 1532 1491 1533 1492 /** -
branches/7.0/src/wp-admin/includes/misc.php
r62089 r62338 1137 1137 */ 1138 1138 function wp_check_locked_posts( $response, $data, $screen_id ) { 1139 $checked = array(); 1140 $is_rtc_enabled = (bool) get_option( 'wp_collaboration_enabled' ); 1139 $checked = array(); 1141 1140 1142 1141 if ( array_key_exists( 'wp-check-locked-posts', $data ) && is_array( $data['wp-check-locked-posts'] ) ) { … … 1154 1153 1155 1154 if ( $user && current_user_can( 'edit_post', $post_id ) ) { 1156 if ( $is_rtc_enabled ) { 1157 $send = array( 1158 /* translators: Collaboration status message for a singular post in the post list. Can be any type of post. */ 1159 'text' => _x( 'Currently being edited', 'post list' ), 1160 'collaborative' => true, 1161 ); 1162 } else { 1163 $send = array( 1164 'name' => $user->display_name, 1165 /* translators: %s: User's display name. */ 1166 'text' => sprintf( __( '%s is currently editing' ), $user->display_name ), 1167 ); 1168 1169 if ( get_option( 'show_avatars' ) ) { 1170 $send['avatar_src'] = get_avatar_url( $user->ID, array( 'size' => 18 ) ); 1171 $send['avatar_src_2x'] = get_avatar_url( $user->ID, array( 'size' => 36 ) ); 1172 } 1155 $send = array( 1156 'name' => $user->display_name, 1157 /* translators: %s: User's display name. */ 1158 'text' => sprintf( __( '%s is currently editing' ), $user->display_name ), 1159 ); 1160 1161 if ( get_option( 'show_avatars' ) ) { 1162 $send['avatar_src'] = get_avatar_url( $user->ID, array( 'size' => 18 ) ); 1163 $send['avatar_src_2x'] = get_avatar_url( $user->ID, array( 'size' => 36 ) ); 1173 1164 } 1174 1165 -
branches/7.0/src/wp-admin/includes/schema.php
r62058 r62338 564 564 // 6.9.0 565 565 'wp_notes_notify' => 1, 566 567 // 7.0.0568 'wp_collaboration_enabled' => 0,569 566 ); 570 567 -
branches/7.0/src/wp-admin/options-writing.php
r62100 r62338 108 108 <?php endforeach; ?> 109 109 </select> 110 </td>111 </tr>112 <tr>113 <th scope="row"><?php _e( 'Collaboration' ); ?></th>114 <td>115 <?php if ( wp_is_collaboration_allowed() ) : ?>116 <label for="wp_collaboration_enabled">117 <input name="wp_collaboration_enabled" type="checkbox" id="wp_collaboration_enabled" value="1" <?php checked( '1', (bool) get_option( 'wp_collaboration_enabled' ) ); ?> />118 <?php _e( "Enable early access to real-time collaboration. Real-time collaboration may affect your website's performance." ); ?>119 </label>120 <?php else : ?>121 <div class="notice notice-warning inline">122 <p><?php _e( '<strong>Note:</strong> Real-time collaboration has been disabled.' ); ?></p>123 </div>124 <?php endif; ?>125 110 </td> 126 111 </tr> -
branches/7.0/src/wp-admin/options.php
r62058 r62338 154 154 'default_link_category', 155 155 'default_post_format', 156 'wp_collaboration_enabled',157 156 ), 158 157 ); -
branches/7.0/src/wp-includes/default-filters.php
r62081 r62338 791 791 add_action( 'init', '_wp_register_default_font_collections' ); 792 792 793 // Collaboration.794 add_action( 'admin_init', 'wp_collaboration_inject_setting' );795 796 793 // Add ignoredHookedBlocks metadata attribute to the template and template part post types. 797 794 add_filter( 'rest_pre_insert_wp_template', 'inject_ignored_hooked_blocks_metadata_attributes' ); -
branches/7.0/src/wp-includes/option.php
r62058 r62338 2887 2887 2888 2888 register_setting( 2889 'writing',2890 'wp_collaboration_enabled',2891 array(2892 'type' => 'boolean',2893 'description' => __( 'Enable Real-Time Collaboration' ),2894 'sanitize_callback' => 'rest_sanitize_boolean',2895 'default' => false,2896 'show_in_rest' => true,2897 )2898 );2899 2900 register_setting(2901 2889 'reading', 2902 2890 'posts_per_page', -
branches/7.0/src/wp-includes/post.php
r62169 r62338 657 657 ) 658 658 ); 659 660 if ( wp_is_collaboration_enabled() ) {661 register_post_type(662 'wp_sync_storage',663 array(664 'labels' => array(665 'name' => __( 'Sync Updates' ),666 'singular_name' => __( 'Sync Update' ),667 ),668 'public' => false,669 '_builtin' => true, /* internal use only. don't use this when registering your own post type. */670 'hierarchical' => false,671 'capabilities' => array(672 'read' => 'do_not_allow',673 'read_private_posts' => 'do_not_allow',674 'create_posts' => 'do_not_allow',675 'publish_posts' => 'do_not_allow',676 'edit_posts' => 'do_not_allow',677 'edit_others_posts' => 'do_not_allow',678 'edit_published_posts' => 'do_not_allow',679 'delete_posts' => 'do_not_allow',680 'delete_others_posts' => 'do_not_allow',681 'delete_published_posts' => 'do_not_allow',682 ),683 'map_meta_cap' => false,684 'publicly_queryable' => false,685 'query_var' => false,686 'rewrite' => false,687 'show_in_menu' => false,688 'show_in_rest' => false,689 'show_ui' => false,690 'can_export' => false,691 'supports' => array( 'custom-fields' ),692 )693 );694 }695 659 696 660 register_post_status( … … 8653 8617 * 8654 8618 * @since 6.3.0 Adds `wp_pattern_sync_status` meta field to the wp_block post type so an unsynced option can be added. 8655 * @since 7.0.0 Adds `_crdt_document` meta field to post types so that CRDT documents can be persisted.8656 8619 * 8657 8620 * @link https://github.com/WordPress/gutenberg/pull/51144 … … 8673 8636 ) 8674 8637 ); 8675 8676 if ( wp_is_collaboration_enabled() ) { 8677 register_meta( 8678 'post', 8679 '_crdt_document', 8680 array( 8681 'auth_callback' => static function ( bool $_allowed, string $_meta_key, int $object_id, int $user_id ): bool { 8682 return user_can( $user_id, 'edit_post', $object_id ); 8683 }, 8684 /* 8685 * Revisions must be disabled because we always want to preserve 8686 * the latest persisted CRDT document, even when a revision is restored. 8687 * This ensures that we can continue to apply updates to a shared document 8688 * and peers can simply merge the restored revision like any other incoming 8689 * update. 8690 * 8691 * If we want to persist CRDT documents alongside revisions in the 8692 * future, we should do so in a separate meta key. 8693 */ 8694 'revisions_enabled' => false, 8695 'show_in_rest' => true, 8696 'single' => true, 8697 'type' => 'string', 8698 ) 8699 ); 8700 } 8701 } 8638 } -
branches/7.0/src/wp-includes/rest-api.php
r62107 r62338 429 429 $icons_controller = new WP_REST_Icons_Controller(); 430 430 $icons_controller->register_routes(); 431 432 // Collaboration.433 if ( wp_is_collaboration_enabled() ) {434 $sync_storage = new WP_Sync_Post_Meta_Storage();435 $sync_server = new WP_HTTP_Polling_Sync_Server( $sync_storage );436 $sync_server->register_routes();437 }438 431 } 439 432 -
branches/7.0/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php
r62075 r62338 230 230 } 231 231 232 $post_lock = wp_check_post_lock( $post->ID );233 $is_draft = 'draft' === $post->post_status || 'auto-draft' === $post->post_status;232 $post_lock_is_active = wp_check_post_lock( $post->ID ); 233 $is_draft = 'draft' === $post->post_status || 'auto-draft' === $post->post_status; 234 234 235 235 /* 236 * In the context of real-time collaboration, all peers are effectively 237 * authors and we don't want to vary behavior based on whether they are the 238 * original author. Always target an autosave revision. 239 * 240 * This avoids the following issue when real-time collaboration is enabled: 241 * 242 * - Autosaves from the original author (if they have the post lock) will 243 * target the saved post. 244 * 245 * - Autosaves from other users are applied to a post revision. 246 * 247 * - If any user reloads a post, they load changes from the author's autosave. 248 * 249 * - The saved post has now diverged from the persisted CRDT document. The 250 * content (and/or title or excerpt) are now "ahead" of the persisted CRDT 251 * document. 252 * 253 * - When the persisted CRDT document is loaded, a diff is computed against 254 * the saved post. This diff is then applied to the in-memory CRDT 255 * document, which can lead to duplicate inserts or deletions. 236 * When a post is still in draft form, updates from the author can directly update the post. 237 * Other autosaves must be stored as per-user autosave revisions. 256 238 */ 257 $is_collaboration_enabled = wp_is_collaboration_enabled(); 258 259 if ( $is_draft && (int) $post->post_author === $user_id && ! $post_lock && ! $is_collaboration_enabled ) { 239 $can_update_author_draft_post = ( 240 $is_draft && 241 (int) $post->post_author === $user_id 242 ); 243 244 $should_update_parent_draft_post = ( 245 ! $post_lock_is_active && $can_update_author_draft_post 246 ); 247 248 if ( $should_update_parent_draft_post ) { 260 249 /* 261 250 * Draft posts for the same author: autosaving updates the post and does not create a revision. … … 264 253 $autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true ); 265 254 } else { 266 // Non-draft posts: create or update the post autosave. Pass the meta data.267 255 $autosave_id = $this->create_post_autosave( (array) $prepared_post, (array) $request->get_param( 'meta' ) ); 268 256 } -
branches/7.0/src/wp-settings.php
r61943 r62338 311 311 require ABSPATH . WPINC . '/abilities-api.php'; 312 312 require ABSPATH . WPINC . '/abilities.php'; 313 require ABSPATH . WPINC . '/collaboration/interface-wp-sync-storage.php';314 require ABSPATH . WPINC . '/collaboration/class-wp-sync-post-meta-storage.php';315 require ABSPATH . WPINC . '/collaboration/class-wp-http-polling-sync-server.php';316 require ABSPATH . WPINC . '/collaboration.php';317 313 require ABSPATH . WPINC . '/rest-api.php'; 318 314 require ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php'; -
branches/7.0/tests/phpunit/tests/rest-api/rest-autosaves-controller.php
r62058 r62338 571 571 572 572 public function test_rest_autosave_draft_post_same_author() { 573 add_filter( 'pre_option_wp_collaboration_enabled', '__return_zero' ); // Zero as false doesn't work for pre-flight options.574 575 573 wp_set_current_user( self::$editor_id ); 576 574 … … 747 745 748 746 public function test_update_item_draft_page_with_parent() { 749 add_filter( 'pre_option_wp_collaboration_enabled', '__return_zero' ); // Zero as false doesn't work for pre-flight options.750 751 747 wp_set_current_user( self::$editor_id ); 752 748 $request = new WP_REST_Request( 'POST', '/wp/v2/pages/' . self::$child_draft_page_id . '/autosaves' ); … … 925 921 ); 926 922 } 927 928 /**929 * When real-time collaboration is enabled, autosaving a draft post by the930 * same author should create a revision instead of updating the post directly.931 */932 public function test_rest_autosave_draft_post_same_author_with_rtc() {933 add_filter( 'pre_option_wp_collaboration_enabled', '__return_true' );934 935 wp_set_current_user( self::$editor_id );936 937 $post_data = array(938 'post_content' => 'Test post content',939 'post_title' => 'Test post title',940 'post_excerpt' => 'Test post excerpt',941 );942 $post_id = wp_insert_post( $post_data );943 944 $autosave_data = array(945 'id' => $post_id,946 'content' => 'Updated post \ content',947 'title' => 'Updated post title',948 );949 950 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' );951 $request->add_header( 'Content-Type', 'application/json' );952 $request->set_body( wp_json_encode( $autosave_data ) );953 954 $response = rest_get_server()->dispatch( $request );955 $new_data = $response->get_data();956 $post = get_post( $post_id );957 958 // With RTC enabled, a revision is created instead of updating the post.959 $this->assertNotSame( $post_id, $new_data['id'] );960 $this->assertSame( $post_id, $new_data['parent'] );961 962 // The autosave revision should have the updated content.963 $this->assertSame( $autosave_data['content'], $new_data['content']['raw'] );964 $this->assertSame( $autosave_data['title'], $new_data['title']['raw'] );965 966 // The draft post should not be updated.967 $this->assertSame( $post_data['post_content'], $post->post_content );968 $this->assertSame( $post_data['post_title'], $post->post_title );969 $this->assertSame( $post_data['post_excerpt'], $post->post_excerpt );970 971 wp_delete_post( $post_id );972 }973 974 /**975 * When real-time collaboration is enabled, autosaving a draft page with976 * a parent should create a revision instead of updating the page directly.977 */978 public function test_update_item_draft_page_with_parent_with_rtc() {979 add_filter( 'pre_option_wp_collaboration_enabled', '__return_true' );980 981 wp_set_current_user( self::$editor_id );982 $request = new WP_REST_Request( 'POST', '/wp/v2/pages/' . self::$child_draft_page_id . '/autosaves' );983 $request->add_header( 'Content-Type', 'application/x-www-form-urlencoded' );984 985 $params = $this->set_post_data(986 array(987 'id' => self::$child_draft_page_id,988 'author' => self::$editor_id,989 )990 );991 992 $request->set_body_params( $params );993 $response = rest_get_server()->dispatch( $request );994 $data = $response->get_data();995 996 // With RTC enabled, a revision is created instead of updating the page.997 $this->assertNotSame( self::$child_draft_page_id, $data['id'] );998 $this->assertSame( self::$child_draft_page_id, $data['parent'] );999 }1000 923 } -
branches/7.0/tests/phpunit/tests/rest-api/rest-settings-controller.php
r62058 r62338 120 120 'default_comment_status', 121 121 'site_icon', // Registered in wp-includes/blocks/site-logo.php 122 'wp_collaboration_enabled',123 122 ); 124 123 -
branches/7.0/tests/qunit/fixtures/wp-api-generated.js
r62081 r62338 11086 11086 "required": false 11087 11087 }, 11088 "wp_collaboration_enabled": {11089 "title": "",11090 "description": "Enable Real-Time Collaboration",11091 "type": "boolean",11092 "required": false11093 },11094 11088 "posts_per_page": { 11095 11089 "title": "Maximum posts per page", … … 14557 14551 "default_category": 1, 14558 14552 "default_post_format": "0", 14559 "wp_collaboration_enabled": false,14560 14553 "posts_per_page": 10, 14561 14554 "show_on_front": "posts",
Note: See TracChangeset
for help on using the changeset viewer.