diff --git a/packages/core-data/src/entities.js b/packages/core-data/src/entities.js
index 87ae920dba6b6..426745ce1b3cf 100644
--- a/packages/core-data/src/entities.js
+++ b/packages/core-data/src/entities.js
@@ -154,6 +154,14 @@ export const defaultEntities = [
baseURLParams: { context: 'edit' },
key: 'stylesheet',
},
+ {
+ label: __( 'Plugins' ),
+ name: 'plugin',
+ kind: 'root',
+ baseURL: '/wp/v2/plugins',
+ baseURLParams: { context: 'edit' },
+ key: 'plugin',
+ },
];
export const kinds = [
diff --git a/packages/edit-site/src/components/list/added-by.js b/packages/edit-site/src/components/list/added-by.js
new file mode 100644
index 0000000000000..685d93fbdfb7f
--- /dev/null
+++ b/packages/edit-site/src/components/list/added-by.js
@@ -0,0 +1,179 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import {
+ __experimentalHStack as HStack,
+ Icon,
+ Tooltip,
+} from '@wordpress/components';
+import { store as coreStore } from '@wordpress/core-data';
+import { useSelect } from '@wordpress/data';
+import { useState } from '@wordpress/element';
+import { layout as themeIcon, plugins as pluginIcon } from '@wordpress/icons';
+import { __ } from '@wordpress/i18n';
+
+const TEMPLATE_POST_TYPE_NAMES = [ 'wp_template', 'wp_template_part' ];
+
+function CustomizedTooltip( { isCustomized, children } ) {
+ if ( ! isCustomized ) {
+ return children;
+ }
+
+ return (
+
+ { children }
+
+ );
+}
+
+function AddedByTheme( { slug, isCustomized } ) {
+ const theme = useSelect(
+ ( select ) => select( coreStore ).getTheme( slug ),
+ [ slug ]
+ );
+
+ return (
+
+
+
+
+
+
+ { theme?.name?.rendered || slug }
+
+ );
+}
+
+function AddedByPlugin( { slug, isCustomized } ) {
+ const plugin = useSelect(
+ ( select ) => select( coreStore ).getPlugin( slug ),
+ [ slug ]
+ );
+
+ return (
+
+
+
+
+
+
+ { plugin?.name || slug }
+
+ );
+}
+
+function AddedByAuthor( { id } ) {
+ const user = useSelect( ( select ) => select( coreStore ).getUser( id ), [
+ id,
+ ] );
+ const [ isImageLoaded, setIsImageLoaded ] = useState( false );
+
+ return (
+
+
+
![]()
setIsImageLoaded( true ) }
+ alt=""
+ src={ user?.avatar_urls[ 48 ] }
+ />
+
+ { user?.nickname }
+
+ );
+}
+
+function AddedBySite() {
+ const { name, logoURL } = useSelect( ( select ) => {
+ const { getEntityRecord, getMedia } = select( coreStore );
+ const siteData = getEntityRecord( 'root', '__unstableBase' );
+
+ return {
+ name: siteData.name,
+ logoURL: siteData?.site_logo
+ ? getMedia( siteData.site_logo )?.source_url
+ : undefined,
+ };
+ }, [] );
+ const [ isImageLoaded, setIsImageLoaded ] = useState( false );
+
+ return (
+
+
+
![]()
setIsImageLoaded( true ) }
+ alt=""
+ src={ logoURL }
+ />
+
+ { name }
+
+ );
+}
+
+export default function AddedBy( { templateType, template } ) {
+ if ( ! template ) {
+ return;
+ }
+
+ if ( TEMPLATE_POST_TYPE_NAMES.includes( templateType ) ) {
+ // Template originally provided by a theme, but customized by a user.
+ // Templates originally didn't have the 'origin' field so identify
+ // older customized templates by checking for no origin and a 'theme'
+ // or 'custom' source.
+ if (
+ template.has_theme_file &&
+ ( template.origin === 'theme' ||
+ ( ! template.origin &&
+ [ 'theme', 'custom' ].includes( template.source ) ) )
+ ) {
+ return (
+
+ );
+ }
+
+ // Template originally provided by a plugin, but customized by a user.
+ if ( template.has_theme_file && template.origin === 'plugin' ) {
+ return (
+
+ );
+ }
+
+ // Template was created from scratch, but has no author. Author support
+ // was only added to templates in WordPress 5.9. Fallback to showing the
+ // site logo and title.
+ if (
+ ! template.has_theme_file &&
+ template.source === 'custom' &&
+ ! template.author
+ ) {
+ return ;
+ }
+ }
+
+ // Simply show the author for templates created from scratch that have an
+ // author or for any other post type.
+ return ;
+}
diff --git a/packages/edit-site/src/components/list/style.scss b/packages/edit-site/src/components/list/style.scss
index 575348c7f65ad..f5ab68cd8bfe3 100644
--- a/packages/edit-site/src/components/list/style.scss
+++ b/packages/edit-site/src/components/list/style.scss
@@ -154,3 +154,55 @@
margin-right: $grid-unit-10;
}
}
+
+.edit-site-list-added-by__icon {
+ display: flex;
+ flex-shrink: 0;
+ position: relative;
+ align-items: center;
+ justify-content: center;
+ width: $grid-unit-40;
+ height: $grid-unit-40;
+ background: $gray-800;
+ border-radius: 100%;
+
+ svg {
+ fill: $white;
+ }
+
+ &.is-customized::after {
+ position: absolute;
+ content: "";
+ background: var(--wp-admin-theme-color);
+ height: $grid-unit-10;
+ width: $grid-unit-10;
+ outline: 2px solid $white;
+ border-radius: 100%;
+ top: -1px;
+ right: -1px;
+ }
+}
+
+.edit-site-list-added-by__avatar {
+ flex-shrink: 0;
+ overflow: hidden;
+ border-radius: 100%;
+ background: $gray-800;
+ width: $grid-unit-40;
+ height: $grid-unit-40;
+
+ img {
+ width: $grid-unit-40;
+ height: $grid-unit-40;
+ object-fit: cover;
+ opacity: 0;
+ transition: opacity 0.1s linear;
+ @include reduce-motion("transition");
+ }
+
+ &.is-loaded {
+ img {
+ opacity: 1;
+ }
+ }
+}
diff --git a/packages/edit-site/src/components/list/table.js b/packages/edit-site/src/components/list/table.js
index 148b6b460c0ff..bcbf48c3939b4 100644
--- a/packages/edit-site/src/components/list/table.js
+++ b/packages/edit-site/src/components/list/table.js
@@ -14,6 +14,7 @@ import { addQueryArgs } from '@wordpress/url';
* Internal dependencies
*/
import Actions from './actions';
+import AddedBy from './added-by';
export default function Table( { templateType } ) {
const { templates, isLoading, postType } = useSelect(
@@ -104,7 +105,10 @@ export default function Table( { templateType } ) {
- { template.theme }
+
|
|