Skip to content
36 changes: 35 additions & 1 deletion lib/compat/wordpress-7.1/collaboration.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,32 @@ function wp_is_collaboration_allowed() {
}
}

if ( ! function_exists( 'wp_is_post_type_collaboration_disabled' ) ) {
/**
* Determines whether real-time collaboration is disabled for a post type.
*
* @since 7.1.0
*
* @param string $post_type Post type name.
* @return bool Whether real-time collaboration is disabled for the post type.
*/
function wp_is_post_type_collaboration_disabled( $post_type ) {
if ( ! post_type_exists( $post_type ) ) {
return true;
}

/**
* Filters whether real-time collaboration is disabled for a post type.
*
* @since 7.1.0
*
* @param bool $disabled Whether real-time collaboration is disabled for the post type.
* @param string $post_type Post type name.
*/
return (bool) apply_filters( 'wp_is_post_type_collaboration_disabled', false, $post_type );
}
}

/**
* Injects the real-time collaboration setting into a global variable.
*
Expand All @@ -229,9 +255,17 @@ function gutenberg_inject_real_time_collaboration_setting() {
$enabled = false;
}

$disabled_post_types = array_values(
array_filter(
get_post_types( array( 'show_in_rest' => true ) ),
'wp_is_post_type_collaboration_disabled'
)
);

wp_add_inline_script(
'wp-core-data',
'window._wpCollaborationEnabled = ' . wp_json_encode( $enabled ) . ';',
'window._wpCollaborationEnabled = ' . wp_json_encode( $enabled ) . ';' .
'window._wpCollaborationDisabledPostTypes = ' . wp_json_encode( $disabled_post_types ) . ';',
'after'
);
}
Expand Down
5 changes: 5 additions & 0 deletions packages/core-data/src/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,11 @@ async function loadPostTypeEntities() {
null
);
},
shouldSync: () =>
! (
Array.isArray( window._wpCollaborationDisabledPostTypes ) &&
window._wpCollaborationDisabledPostTypes.includes( name )
),
};

return entity;
Expand Down
51 changes: 51 additions & 0 deletions packages/core-data/src/test/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,20 @@ describe( 'prePersistPostType', () => {

describe( 'loadPostTypeEntities', () => {
let originalCollaborationEnabled;
let originalCollaborationDisabledPostTypes;

beforeEach( () => {
apiFetch.mockReset();
applyPostChangesToCRDTDoc.mockReset();
originalCollaborationEnabled = window._wpCollaborationEnabled;
originalCollaborationDisabledPostTypes =
window._wpCollaborationDisabledPostTypes;
} );

afterEach( () => {
window._wpCollaborationEnabled = originalCollaborationEnabled;
window._wpCollaborationDisabledPostTypes =
originalCollaborationDisabledPostTypes;
} );

it( 'should include custom taxonomy rest_bases in synced properties when collaboration is enabled', async () => {
Expand Down Expand Up @@ -224,6 +229,52 @@ describe( 'loadPostTypeEntities', () => {
expect( syncedProperties ).not.toContain( 'tags' );
} );

it( 'should sync post type entities by default', async () => {
window._wpCollaborationEnabled = false;
window._wpCollaborationDisabledPostTypes = undefined;

const mockPostTypes = {
post: {
name: 'Posts',
rest_base: 'posts',
rest_namespace: 'wp/v2',
},
};

apiFetch.mockResolvedValueOnce( mockPostTypes );

const postTypeLoader = additionalEntityConfigLoaders.find(
( loader ) => loader.kind === 'postType'
);
const entities = await postTypeLoader.loadEntities();
const postEntity = entities.find( ( e ) => e.name === 'post' );

expect( postEntity.syncConfig.shouldSync() ).toBe( true );
} );

it( 'should not sync post type entities disabled for collaboration', async () => {
window._wpCollaborationEnabled = false;
window._wpCollaborationDisabledPostTypes = [ 'book' ];

const mockPostTypes = {
book: {
name: 'Books',
rest_base: 'books',
rest_namespace: 'wp/v2',
},
};

apiFetch.mockResolvedValueOnce( mockPostTypes );

const postTypeLoader = additionalEntityConfigLoaders.find(
( loader ) => loader.kind === 'postType'
);
const entities = await postTypeLoader.loadEntities();
const bookEntity = entities.find( ( e ) => e.name === 'book' );

expect( bookEntity.syncConfig.shouldSync() ).toBe( false );
} );

it( 'should skip taxonomy rest_base when taxonomy is not found in fetched taxonomies', async () => {
window._wpCollaborationEnabled = true;

Expand Down
12 changes: 11 additions & 1 deletion packages/editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
getRenderingMode,
getCurrentPost,
getCurrentPostType,
getCurrentPostId,
getEditorSettings,
getCurrentPostRevisionsCount,
} from './selectors';
Expand Down Expand Up @@ -598,13 +599,22 @@ export const isCollaborationEnabledForCurrentPost = createRegistrySelector(
}

const currentPostType = getCurrentPostType( state );
const currentPostId = getCurrentPostId( state );
const entityConfig = select( coreStore ).getEntityConfig(
'postType',
currentPostType
);
const syncConfig = entityConfig?.syncConfig;

return Boolean(
entityConfig?.syncConfig && window._wpCollaborationEnabled
syncConfig &&
syncConfig.supportsPersistence &&
window._wpCollaborationEnabled &&
false !==
syncConfig.shouldSync?.(
Comment thread
maxschmeling marked this conversation as resolved.
Resolved
`postType/${ currentPostType }`,
currentPostId
)
);
}
);
69 changes: 69 additions & 0 deletions packages/editor/src/store/test/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { store as preferencesStore } from '@wordpress/preferences';
import {
getDefaultRenderingMode,
getPostBlocksByName,
isCollaborationEnabledForCurrentPost,
} from '../private-selectors';
import { lock } from '../../lock-unlock';

describe( 'getPostBlocksByName', () => {
const state = {
Expand Down Expand Up @@ -86,6 +88,73 @@ describe( 'getPostBlocksByName', () => {
} );
} );

describe( 'isCollaborationEnabledForCurrentPost', () => {
let originalCollaborationEnabled;

beforeEach( () => {
originalCollaborationEnabled = window._wpCollaborationEnabled;
window._wpCollaborationEnabled = true;
} );

afterEach( () => {
window._wpCollaborationEnabled = originalCollaborationEnabled;
} );

function setupRegistry( {
collaborationSupported = true,
syncConfig = {},
} = {} ) {
isCollaborationEnabledForCurrentPost.registry = {
select: ( store ) => {
if ( store === coreStore ) {
const selectors = {
getEntityConfig: () => ( { syncConfig } ),
};
lock( selectors, {
isCollaborationSupported: () => collaborationSupported,
} );
return selectors;
}
},
};
}

it( 'returns true when the current post type sync config should sync', () => {
const shouldSync = jest.fn( () => true );
setupRegistry( {
syncConfig: { shouldSync, supportsPersistence: true },
} );

const state = { postType: 'book', postId: 123 };

expect( isCollaborationEnabledForCurrentPost( state ) ).toBe( true );
expect( shouldSync ).toHaveBeenCalledWith( 'postType/book', 123 );
} );

it( 'returns false when the current post type sync config does not support persistence', () => {
const shouldSync = jest.fn( () => true );
setupRegistry( { syncConfig: { shouldSync } } );

const state = { postType: 'book', postId: 123 };

expect( isCollaborationEnabledForCurrentPost( state ) ).toBe( false );
expect( shouldSync ).not.toHaveBeenCalled();
} );

it( 'returns false when the current post type sync config should not sync', () => {
setupRegistry( {
syncConfig: {
shouldSync: () => false,
supportsPersistence: true,
},
} );

const state = { postType: 'book', postId: 123 };

expect( isCollaborationEnabledForCurrentPost( state ) ).toBe( false );
} );
} );

describe( 'getDefaultRenderingMode', () => {
function setupRegistry( {
supportsEditor = true,
Expand Down
Loading