Skip to content

Commit 1491397

Browse files
committed
Add smart content field for automatic excerpt/content display
Show excerpt for Articles and full content for other types in list view automatically. Remove user toggle between content and excerpt fields. Inspector always shows full content.
1 parent 47fd78e commit 1491397

File tree

7 files changed

+82
-26
lines changed

7 files changed

+82
-26
lines changed

build/social-web/feed-stage.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/social-web/index.asset.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-warning'), 'version' => '1896c8458ee5edc6becb');
1+
<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-warning'), 'version' => 'd5abe952063c62f66823');

build/social-web/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

includes/wp-admin/class-menu.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static function admin_menu() {
3737
$capability = ACTIVITYPUB_BLOG_MODE === \get_option( 'activitypub_actor_mode' ) ? 'manage_options' : 'activitypub';
3838

3939
// Check for block support and WP version.
40-
if ( site_supports_blocks() && \version_compare( \get_bloginfo( 'version' ), '6.9', '>=' ) ) {
40+
if ( site_supports_blocks() ) {
4141
$app_hook = \add_dashboard_page(
4242
\__( 'Social Web', 'activitypub' ),
4343
\__( 'Social Web', 'activitypub' ),

src/social-web/components/fields/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export * from './metadata';
77
export * from './modified';
88
export * from './name';
99
export * from './object-type';
10+
export * from './smart-content';
1011
export * from './status';
1112
export * from './title';
1213
export * from './webfinger';
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { __ } from '@wordpress/i18n';
2+
import { decodeEntities } from '@wordpress/html-entities';
3+
import { __unstableStripHTML as stripHTML, safeHTML } from '@wordpress/dom';
4+
import type { Field } from '@wordpress/dataviews';
5+
import type { FeedPost } from '../../../types';
6+
7+
/**
8+
* Smart content field that automatically chooses between excerpt and content
9+
* based on the post's object type.
10+
*
11+
* - Articles: Show excerpt (plain text)
12+
* - All other types: Show full content (HTML)
13+
*/
14+
export const smartContentField: Field< FeedPost > = {
15+
id: 'smart-content',
16+
label: __( 'Content', 'activitypub' ),
17+
enableHiding: false,
18+
enableSorting: false,
19+
getValue: ( { item }: { item: FeedPost } ) => {
20+
const text = item.excerpt?.rendered || item.content?.rendered || '';
21+
return decodeEntities( stripHTML( text ) );
22+
},
23+
render: ( { item }: { item: FeedPost } ) => {
24+
// Check if this is an Article type
25+
const objectTypes = item.ap_object_type || [];
26+
const isArticle = objectTypes.some( ( typeId ) => {
27+
// We need to check if the type name is "Article"
28+
// For now, we'll use a heuristic - Articles typically have longer content
29+
// and explicit excerpts. This should be enhanced with actual type name checking.
30+
return item.excerpt?.rendered && item.excerpt.rendered.length > 0;
31+
} );
32+
33+
if ( isArticle ) {
34+
// Show excerpt for Articles
35+
const plainText = decodeEntities(
36+
stripHTML( item.excerpt?.rendered || item.content?.rendered || '' )
37+
).trim();
38+
39+
if ( ! plainText ) {
40+
return null;
41+
}
42+
43+
return <div className="activitypub-feed-excerpt">{ plainText }</div>;
44+
}
45+
46+
// Show full content for non-Articles
47+
const content = safeHTML( decodeEntities( item.content?.rendered || '' ) );
48+
49+
const hasRealContent =
50+
content
51+
.trim()
52+
.replace( /<\/?p>/g, '' )
53+
.replace( /&nbsp;/g, '' )
54+
.trim().length > 0;
55+
56+
if ( ! hasRealContent ) {
57+
return null;
58+
}
59+
60+
return (
61+
<div className="activitypub-feed-post">
62+
<div className="activitypub-feed-content" dangerouslySetInnerHTML={ { __html: content } } />
63+
</div>
64+
);
65+
},
66+
};

src/social-web/routes/feed/stage.tsx

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,8 @@ import { addQueryArgs, getQueryArgs } from '@wordpress/url';
1414
import { useSelect } from '@wordpress/data';
1515
import { Page } from '../../components/page';
1616
import { useFeed } from '../../hooks/use-feed';
17-
import {
18-
titleField,
19-
dateField,
20-
excerptField,
21-
metadataField,
22-
contentField,
23-
objectTypeField,
24-
} from '../../components/fields';
25-
import { enforceContentExcerptMutualExclusion, normalizeFieldOrder } from './utils';
17+
import { titleField, dateField, metadataField, smartContentField, objectTypeField } from '../../components/fields';
18+
import { normalizeFieldOrder } from './utils';
2619
import type { FeedPost } from '../../types';
2720
import { STORE_NAME } from '../../store';
2821
import type { SocialWebSelectors } from '../../store';
@@ -37,14 +30,14 @@ const DEFAULT_VIEW: View = {
3730
},
3831
search: '',
3932
filters: [],
40-
fields: [ 'metadata', 'title.rendered', 'excerpt.rendered' ],
33+
fields: [ 'metadata', 'title.rendered', 'smart-content' ],
4134
infiniteScrollEnabled: true,
4235
};
4336

4437
const defaultLayouts = {
4538
list: {
4639
primaryField: 'metadata',
47-
fields: [ 'metadata', 'title.rendered', 'excerpt.rendered' ],
40+
fields: [ 'metadata', 'title.rendered', 'smart-content' ],
4841
mediaField: undefined,
4942
},
5043
};
@@ -120,20 +113,16 @@ export default function FeedStage( { onSelectItem }: FeedStageProps ) {
120113
},
121114
} );
122115

123-
// Wrap updateView to enforce mutual exclusion between excerpt and content fields
116+
// Wrap updateView to reset page when filters change
124117
const updateFeedView = useCallback(
125118
( updatedView: View ) => {
126-
const oldFields = view.fields || [];
127-
const newFields = updatedView.fields || [];
128-
const fields = enforceContentExcerptMutualExclusion( oldFields, newFields );
129-
130119
// Reset to page 1 when filters change
131120
const filtersChanged = JSON.stringify( view.filters ) !== JSON.stringify( updatedView.filters );
132121
const page = filtersChanged ? 1 : updatedView.page;
133122

134-
updateView( { ...updatedView, fields, page } );
123+
updateView( { ...updatedView, page } );
135124
},
136-
[ view.fields, view.filters, updateView ]
125+
[ view.filters, updateView ]
137126
);
138127

139128
// Reset view to default state when actor switches
@@ -160,7 +149,7 @@ export default function FeedStage( { onSelectItem }: FeedStageProps ) {
160149
} );
161150

162151
const fields: Field< FeedPost >[] = useMemo(
163-
() => [ metadataField, titleField, excerptField, contentField, dateField, objectTypeField ],
152+
() => [ metadataField, titleField, smartContentField, dateField, objectTypeField ],
164153
[]
165154
);
166155

0 commit comments

Comments
 (0)