Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/social-web/feed-stage.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/social-web/index.asset.php
Original file line number Diff line number Diff line change
@@ -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' => '658866a5e77c1bf57d37');
<?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');
2 changes: 1 addition & 1 deletion build/social-web/index.js

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions includes/class-post-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,15 @@ function ( $params ) {
'sanitize_callback' => 'absint',
);

$params['ap_object_type'] = array(
'description' => 'Filter posts by ActivityPub object type.',
'type' => 'array',
'items' => array(
'type' => 'integer',
'minimum' => 0,
),
);

return $params;
}
);
Expand Down Expand Up @@ -743,6 +752,19 @@ public static function filter_ap_post_by_user( $args, $request ) {
'compare' => '=',
);

// Filter by object type if provided.
if ( ! empty( $request['ap_object_type'] ) ) {
if ( ! isset( $args['tax_query'] ) ) {
$args['tax_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
}

$args['tax_query'][] = array(
'taxonomy' => 'ap_object_type',
'field' => 'term_id',
'terms' => $request['ap_object_type'],
);
}

return $args;
}

Expand Down
1 change: 1 addition & 0 deletions src/social-web/components/fields/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './follow-status';
export * from './metadata';
export * from './modified';
export * from './name';
export * from './object-type';
export * from './status';
export * from './title';
export * from './webfinger';
44 changes: 44 additions & 0 deletions src/social-web/components/fields/object-type/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { __ } from '@wordpress/i18n';
import { resolveSelect } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import type { Term } from '@wordpress/core-data';
import type { Field } from '@wordpress/dataviews';
import type { FeedPost } from '../../../types';

export const objectTypeField: Field< FeedPost > = {
id: 'ap_object_type',
type: 'integer',
label: __( 'Type', 'activitypub' ),
enableHiding: false,
enableSorting: false,
getValue: ( { item }: { item: FeedPost } ): number => item.ap_object_type?.[ 0 ],
getElements: async (): Promise< { value: number; label: string }[] > => {
const translations: Record< string, string > = {
// @see Base_Object::TYPES
Article: __( 'Articles', 'activitypub' ),
Audio: __( 'Music & Podcasts', 'activitypub' ),
Document: __( 'Documents & Files', 'activitypub' ),
Event: __( 'Events & Meetups', 'activitypub' ),
Image: __( 'Photos & Images', 'activitypub' ),
Note: __( 'Notes & Updates', 'activitypub' ),
Page: __( 'Pages', 'activitypub' ),
Place: __( 'Places & Locations', 'activitypub' ),
Video: __( 'Videos', 'activitypub' ),
};
const records: Term[] = await resolveSelect( coreDataStore ).getEntityRecords( 'taxonomy', 'ap_object_type' );

if ( ! records ) {
return [];
}

// Map all terms with translations for known types
return records.map( ( term: Term ): { value: number; label: string } => ( {
value: term.id,
label: translations[ term.name ] || term.name,
} ) );
},
render: (): null => null,
filterBy: {
operators: [ 'is' ],
},
};
29 changes: 27 additions & 2 deletions src/social-web/hooks/use-feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { useEntityRecords } from '@wordpress/core-data';
import { useMemo } from '@wordpress/element';
import type { FeedPost } from '../types';

interface Filter {
field: string;
operator: string;
value: any;
}

interface UseFeedParams {
perPage?: number;
page?: number;
Expand All @@ -10,6 +16,7 @@ interface UseFeedParams {
search?: string;
userId?: number;
fields?: string[];
filters?: Filter[];
}

interface UseFeedReturn {
Expand All @@ -27,7 +34,19 @@ export function useFeed( {
order = 'desc',
search = '',
userId,
fields = [ 'id', 'date', 'modified', 'title', 'excerpt', 'content', 'actor_info', 'status', 'link' ],
fields = [
'id',
'date',
'modified',
'title',
'excerpt',
'content',
'actor_info',
'status',
'link',
'ap_object_type',
],
filters = [],
}: UseFeedParams = {} ): UseFeedReturn {
// Don't fetch if userId is not set
const enabled = userId !== null && userId !== undefined;
Expand All @@ -47,8 +66,14 @@ export function useFeed( {
args.user_id = userId;
}

// Extract ap_object_type filter from filters array
const apObjectTypeFilter = filters.find( ( f ) => f.field === 'ap_object_type' );
if ( apObjectTypeFilter?.value !== undefined ) {
args.ap_object_type = apObjectTypeFilter.value;
}

return args;
}, [ perPage, page, orderBy, order, search, userId, fields, enabled ] );
}, [ perPage, page, orderBy, order, search, userId, fields, enabled, filters ] );

const { records, hasResolved, isResolving, totalItems, totalPages } = useEntityRecords< FeedPost >(
'postType',
Expand Down
28 changes: 23 additions & 5 deletions src/social-web/routes/feed/stage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ import { addQueryArgs, getQueryArgs } from '@wordpress/url';
import { useSelect } from '@wordpress/data';
import { Page } from '../../components/page';
import { useFeed } from '../../hooks/use-feed';
import { titleField, dateField, excerptField, metadataField, contentField } from '../../components/fields';
import {
titleField,
dateField,
excerptField,
metadataField,
contentField,
objectTypeField,
} from '../../components/fields';
import { enforceContentExcerptMutualExclusion, normalizeFieldOrder } from './utils';
import type { FeedPost } from '../../types';
import { STORE_NAME } from '../../store';
Expand Down Expand Up @@ -120,9 +127,13 @@ export default function FeedStage( { onSelectItem }: FeedStageProps ) {
const newFields = updatedView.fields || [];
const fields = enforceContentExcerptMutualExclusion( oldFields, newFields );

updateView( { ...updatedView, fields } );
// Reset to page 1 when filters change
const filtersChanged = JSON.stringify( view.filters ) !== JSON.stringify( updatedView.filters );
const page = filtersChanged ? 1 : updatedView.page;

updateView( { ...updatedView, fields, page } );
},
[ view.fields, updateView ]
[ view.fields, view.filters, updateView ]
);

// Reset view to default state when actor switches
Expand All @@ -145,10 +156,11 @@ export default function FeedStage( { onSelectItem }: FeedStageProps ) {
order: view.sort?.direction || 'desc',
search: view.search || '',
userId: activeActorId,
filters: view.filters,
} );

const fields: Field< FeedPost >[] = useMemo(
() => [ metadataField, titleField, excerptField, contentField, dateField ],
() => [ metadataField, titleField, excerptField, contentField, dateField, objectTypeField ],
[]
);

Expand Down Expand Up @@ -238,7 +250,13 @@ export default function FeedStage( { onSelectItem }: FeedStageProps ) {
lastProcessedPage.current = currentPage;
setIsLoadingMore( false );
}
}, [ feed, normalizedView.page, normalizedView.search, normalizedView.infiniteScrollEnabled ] );
}, [
feed,
normalizedView.page,
normalizedView.search,
normalizedView.infiniteScrollEnabled,
normalizedView.filters,
] );

return (
<Page
Expand Down
1 change: 1 addition & 0 deletions src/social-web/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export interface FeedPost {
};
comment_status: string;
ping_status: string;
ap_object_type?: number[];
actor_info?: ActorInfo;
}

Expand Down