true ) ),
'wp_is_post_type_collaboration_disabled'
)
);
wp_add_inline_script(
'wp-core-data',
'window._wpCollaborationEnabled = ' . wp_json_encode( $enabled ) . ';' .
'window._wpCollaborationDisabledPostTypes = ' . wp_json_encode( $disabled_post_types ) . ';',
'after'
);
}
add_action( 'admin_init', 'gutenberg_inject_real_time_collaboration_setting' );
/**
* Core adds an option with the default value, so we need to set the option to
* our intended default when the Gutenberg plugin is activated, provided
* collaboration is allowed.
*/
function gutenberg_set_collaboration_option_on_activation() {
if ( wp_is_collaboration_allowed() ) {
update_option( 'wp_collaboration_enabled', '1' );
}
}
add_action( 'activate_' . plugin_basename( dirname( __DIR__, 3 ) . '/gutenberg.php' ), 'gutenberg_set_collaboration_option_on_activation' );
/**
* Modifies the post list UI and heartbeat responses for real-time collaboration.
*
* When RTC is enabled, hides the lock icon and user avatar, replaces the
* user-specific lock text with "Currently being edited", changes the "Edit"
* row action to "Join", and re-enables controls that core normally hides
* for locked posts (since collaborative editing is possible).
*
* @global string $pagenow The filename of the current screen.
*/
function gutenberg_post_list_collaboration_ui() {
global $pagenow;
if ( ! wp_is_collaboration_enabled() ) {
return;
}
// Heartbeat filter applies globally (not just edit.php) since the
// heartbeat API can fire from any admin page.
add_filter( 'heartbeat_received', 'gutenberg_filter_locked_posts_heartbeat_for_rtc', 20 );
// CSS, JS, and row action overrides only apply on the posts list page.
if ( 'edit.php' !== $pagenow ) {
return;
}
add_action( 'admin_head', 'gutenberg_post_list_collaboration_styles' );
add_filter( 'gettext', 'gutenberg_filter_locked_post_text_for_rtc', 10, 3 );
add_filter( 'post_row_actions', 'gutenberg_post_list_collaboration_row_actions', 10, 2 );
add_filter( 'page_row_actions', 'gutenberg_post_list_collaboration_row_actions', 10, 2 );
}
add_action( 'admin_init', 'gutenberg_post_list_collaboration_ui' );
/**
* Filters the heartbeat response to remove user-specific lock information
* when real-time collaboration is enabled.
*
* WordPress core's wp_check_locked_posts() runs at priority 10 and populates
* the 'wp-check-locked-posts' key with user name, avatar, and text. This
* filter runs at priority 20 to replace that data with a generic message,
* preventing user-specific lock info from reaching the client.
*
* @param array $response The heartbeat response.
* @return array Modified heartbeat response.
*/
function gutenberg_filter_locked_posts_heartbeat_for_rtc( $response ) {
if ( ! empty( $response['wp-check-locked-posts'] ) ) {
foreach ( $response['wp-check-locked-posts'] as $key => $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() {
?>
post_type ) ) {
return $actions;
}
$title = _draft_or_post_title( $post->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;
}