array( 'name' => __( 'Sync Updates', 'gutenberg' ), 'singular_name' => __( 'Sync Update', 'gutenberg' ), ), 'public' => false, 'hierarchical' => false, 'capabilities' => array( 'read' => 'do_not_allow', 'read_private_posts' => 'do_not_allow', 'create_posts' => 'do_not_allow', 'publish_posts' => 'do_not_allow', 'edit_posts' => 'do_not_allow', 'edit_others_posts' => 'do_not_allow', 'edit_published_posts' => 'do_not_allow', 'delete_posts' => 'do_not_allow', 'delete_others_posts' => 'do_not_allow', 'delete_published_posts' => 'do_not_allow', ), 'map_meta_cap' => false, 'publicly_queryable' => false, 'query_var' => false, 'rewrite' => false, 'show_in_menu' => false, 'show_in_rest' => false, 'show_ui' => false, 'supports' => array( 'custom-fields' ), ) ); } add_action( 'init', 'gutenberg_register_sync_storage_post_type' ); } if ( ! function_exists( 'gutenberg_register_collaboration_rest_routes' ) ) { /** * Registers REST API routes for collaborative editing. */ function gutenberg_register_collaboration_rest_routes(): void { $sync_storage = new WP_Sync_Post_Meta_Storage(); $sync_server = new WP_HTTP_Polling_Sync_Server( $sync_storage ); $sync_server->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_collaboration_rest_routes' ); } if ( ! function_exists( 'wp_collaboration_register_meta' ) ) { /** * Registers post meta for persisting CRDT documents. */ function gutenberg_rest_api_crdt_post_meta() { // This string must match WORDPRESS_META_KEY_FOR_CRDT_DOC_PERSISTENCE in @wordpress/sync. $persisted_crdt_post_meta_key = '_crdt_document'; register_meta( 'post', $persisted_crdt_post_meta_key, array( 'auth_callback' => static function ( bool $_allowed, string $_meta_key, int $object_id, int $user_id ): bool { return user_can( $user_id, 'edit_post', $object_id ); }, /* * Revisions must be disabled because we always want to preserve * the latest persisted CRDT document, even when a revision is restored. * This ensures that we can continue to apply updates to a shared document * and peers can simply merge the restored revision like any other incoming * update. * * If we want to persist CRDT documents alongside revisions in the * future, we should do so in a separate meta key. */ 'revisions_enabled' => false, 'show_in_rest' => array( 'schema' => array( 'type' => 'string', 'context' => array( 'edit' ), ), ), 'single' => true, 'type' => 'string', ) ); } add_action( 'init', 'gutenberg_rest_api_crdt_post_meta' ); } if ( ! function_exists( 'wp_collaboration_inject_setting' ) ) { /** * Registers the real-time collaboration setting. */ function gutenberg_register_real_time_collaboration_setting() { $option_name = 'wp_collaboration_enabled'; register_setting( 'writing', $option_name, array( 'type' => 'boolean', 'description' => __( 'Enable Real-Time Collaboration', 'gutenberg' ), 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => true, 'show_in_rest' => true, ) ); add_settings_field( $option_name, __( 'Collaboration', 'gutenberg' ), function () use ( $option_name ) { $option_value = get_option( $option_name ); if ( wp_is_collaboration_allowed() ) : ?>
' . __( '%s Real-time collaboration has been disabled.', 'gutenberg' ) . '

', '' . __( 'Note:', 'gutenberg' ) . '' ); ?>
$lock_data ) { $response['wp-check-locked-posts'][ $key ]['text'] = __( 'Currently being edited', 'gutenberg' ); unset( $response['wp-check-locked-posts'][ $key ]['avatar_src'] ); unset( $response['wp-check-locked-posts'][ $key ]['avatar_src_2x'] ); } } return $response; } /** * Outputs CSS to hide the post lock icon and user avatar in the post list * when real-time collaboration is enabled. * * Also re-enables checkboxes and row actions that WordPress core hides for * locked posts, since collaborative editing means the post is not exclusively * locked. Toggles "Edit" / "Join" action link text via the * `.wp-collaborative-editing` class that the heartbeat already manages. */ function gutenberg_post_list_collaboration_styles() { ?> ID ); /* * Each state is rendered as ``. * The toggle classes sit on the outer rather than the so they * fall outside core's responsive selector `.row-actions span a` at * <=782px, which otherwise outranks our class selectors and (a) leaves * both labels visible on unlocked rows and (b) forces `display: inline` * on the visible Join link to misalign with sibling row actions. The * visible label is still a direct text child of , so core's mobile * font-size rule * .row-actions span { font-size: 0; } * .row-actions span a { font-size: 13px; } * still reaches it — that's the fix for the original "Edit invisible * at 0px on mobile" regression. CSS in * gutenberg_post_list_collaboration_styles() flips visibility on the * outer spans based on the row's `wp-locked` class, which core's * inline-edit-post.js maintains in response to heartbeat ticks. */ $actions['edit'] = sprintf( '%3$s' . '%5$s', esc_url( get_edit_post_link( $post->ID ) ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Edit “%s”' ), $title ) ), __( 'Edit' ), /* translators: %s: Post title. */ esc_attr( sprintf( __( 'Join editing “%s”', 'gutenberg' ), $title ) ), /* translators: Action link text for a singular post in the post list. Can be any type of post. */ _x( 'Join', 'post list', 'gutenberg' ) ); return $actions; }