diff --git a/build/author/block.json b/build/author/block.json
new file mode 100644
index 0000000..e49b166
--- /dev/null
+++ b/build/author/block.json
@@ -0,0 +1,66 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "query-filter/author",
+ "version": "0.1.0",
+ "title": "Author Filter",
+ "category": "theme",
+ "icon": "filter",
+ "description": "Allows users to filter by author when placed wihin a query loop block",
+ "ancestor": [
+ "core/query"
+ ],
+ "usesContext": [
+ "queryId",
+ "query"
+ ],
+ "supports": {
+ "html": false,
+ "className": true,
+ "customClassName": true,
+ "color": {
+ "background": true,
+ "text": true
+ },
+ "typography": {
+ "fontSize": true,
+ "textAlign": true,
+ "lineHeight": true,
+ "__experimentalFontFamily": true,
+ "__experimentalFontWeight": true,
+ "__experimentalFontStyle": true,
+ "__experimentalTextTransform": true,
+ "__experimentalTextDecoration": true,
+ "__experimentalLetterSpacing": true,
+ "__experimentalDefaultControls": {
+ "fontSize": true
+ }
+ },
+ "spacing": {
+ "margin": true,
+ "padding": true,
+ "blockGap": true
+ },
+ "interactivity": {
+ "clientNavigation": true
+ }
+ },
+ "attributes": {
+ "emptyLabel": {
+ "type": "string",
+ "default": ""
+ },
+ "label": {
+ "type": "string"
+ },
+ "showLabel": {
+ "type": "boolean",
+ "default": true
+ }
+ },
+ "textdomain": "query-filter",
+ "editorScript": "file:./index.js",
+ "viewScriptModule": "query-filter-author-view-script-module",
+ "style": "query-filter-view",
+ "render": "file:./render.php"
+}
\ No newline at end of file
diff --git a/build/author/index.asset.php b/build/author/index.asset.php
new file mode 100644
index 0000000..156f142
--- /dev/null
+++ b/build/author/index.asset.php
@@ -0,0 +1 @@
+ array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n'), 'version' => 'd22a929de73f1aa107a9');
diff --git a/build/author/index.js b/build/author/index.js
new file mode 100644
index 0000000..fba60fc
--- /dev/null
+++ b/build/author/index.js
@@ -0,0 +1 @@
+(()=>{"use strict";const e=window.wp.blocks,l=window.wp.i18n,r=window.wp.blockEditor,t=window.wp.components,o=window.ReactJSXRuntime,i=JSON.parse('{"UU":"query-filter/author"}');(0,e.registerBlockType)(i.UU,{edit:function({attributes:e,setAttributes:i}){const{emptyLabel:s,label:n,showLabel:a}=e;return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(r.InspectorControls,{children:(0,o.jsxs)(t.PanelBody,{title:(0,l.__)("Author Filter Settings","query-filter"),children:[(0,o.jsx)(t.TextControl,{label:(0,l.__)("Label","query-filter"),value:n,defaultValue:(0,l.__)("Author","query-filter"),help:(0,l.__)("If empty then no label will be shown","query-filter"),onChange:e=>i({label:e})}),(0,o.jsx)(t.ToggleControl,{label:(0,l.__)("Show Label","query-filter"),checked:a,onChange:e=>i({showLabel:e})}),(0,o.jsx)(t.TextControl,{label:(0,l.__)("Empty Choice Label","query-filter"),value:s,placeholder:(0,l.__)("All Authors","query-filter"),onChange:e=>i({emptyLabel:e})})]})}),(0,o.jsxs)("div",{...(0,r.useBlockProps)({className:"wp-block-query-filter"}),children:[a&&(0,o.jsx)("label",{className:"wp-block-query-filter-author__label wp-block-query-filter__label",children:n||(0,l.__)("Author","query-filter")}),(0,o.jsxs)("select",{className:"wp-block-query-filter-author__select wp-block-query-filter__select",inert:!0,children:[(0,o.jsx)("option",{children:s||(0,l.__)("All Authors","query-filter")}),(0,o.jsx)("option",{children:(0,l.__)("Sample Author 1","query-filter")}),(0,o.jsx)("option",{children:(0,l.__)("Sample Author 2","query-filter")})]})]})]})}})})();
\ No newline at end of file
diff --git a/build/author/render.php b/build/author/render.php
new file mode 100644
index 0000000..88d344d
--- /dev/null
+++ b/build/author/render.php
@@ -0,0 +1,86 @@
+context['query']['inherit'] ) {
+ $query_var = 'query-author'; // Changed from query-post_type
+ $page_var = 'page';
+ $base_url = str_replace( '/page/' . get_query_var( 'paged' ), '', remove_query_arg( [ $query_var, $page_var ] ) );
+} else {
+ $query_id = $block->context['queryId'] ?? 0;
+ $query_var = sprintf( 'query-%d-author', $query_id ); // Changed from query-%d-post_type
+ $page_var = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page';
+ $base_url = remove_query_arg( [ $query_var, $page_var ] );
+}
+
+// Determine relevant post types for filtering authors.
+$relevant_post_types = [];
+
+// Get post types from block context if they are explicitly set.
+if ( ! empty( $block->context['query']['postType'] ) ) {
+ $types = is_array( $block->context['query']['postType'] ) ? $block->context['query']['postType'] : explode( ',', $block->context['query']['postType'] );
+ $relevant_post_types = array_merge( $relevant_post_types, array_map( 'trim', $types ) );
+}
+
+// Support for enhanced query block (multiple_posts).
+// if ( ! empty( $block->context['query']['multiple_posts'] ) && is_array( $block->context['query']['multiple_posts'] ) ) {
+// $relevant_post_types = array_merge( $relevant_post_types, $block->context['query']['multiple_posts'] );
+// }
+
+// Handle inherited query.
+if ( $block->context['query']['inherit'] && empty( $relevant_post_types ) ) {
+ $main_query_post_type = $wp_query->get( 'post_type' );
+
+ if ( empty( $main_query_post_type ) || 'any' === $main_query_post_type ) {
+ // If main query is 'any' or not specific, consider all public, viewable post types.
+ $public_types = get_post_types( [ 'public' => true, 'show_ui' => true ], 'names' );
+ // Exclude 'attachment' by default, similar to how Query Loop block might treat 'any'.
+ if ( ! get_option( 'wp_attachment_pages_enabled' ) ) {
+ unset( $public_types['attachment'] );
+ }
+ $relevant_post_types = array_merge( $relevant_post_types, array_values( $public_types ) );
+ } else {
+ $relevant_post_types = array_merge( $relevant_post_types, (array) $main_query_post_type );
+ }
+}
+
+$relevant_post_types = array_values( array_unique( array_filter( $relevant_post_types ) ) );
+
+$user_args = [
+ 'capability' => [ 'publish_posts' ], // Users who can publish posts
+ 'fields' => [ 'ID', 'display_name' ],
+ 'orderby' => 'display_name',
+ 'order' => 'ASC',
+];
+
+// If specific post types are identified for the query, filter authors by those.
+// Otherwise, get authors who have published any post (adhering to 'authors' role).
+if ( ! empty( $relevant_post_types ) ) {
+ $user_args['has_published_posts'] = $relevant_post_types;
+} else {
+ // If $relevant_post_types is empty, it implies the query is for "any" post type.
+ // So, we list authors who have published any type of content.
+ // `get_users` with `who => 'authors'` covers users with publishing roles.
+ // Setting `has_published_posts = true` explicitly queries for posts in public post types.
+ $user_args['has_published_posts'] = true;
+}
+
+$authors = get_users( $user_args );
+
+if ( empty( $authors ) ) {
+ return;
+}
+?>
+
+
'wp-block-query-filter' ] ); ?> data-wp-interactive="query-filter" data-wp-context="{}">
+
+
+
diff --git a/inc/namespace.php b/inc/namespace.php
index 0bd4afa..21cc3d0 100644
--- a/inc/namespace.php
+++ b/inc/namespace.php
@@ -52,6 +52,7 @@ function action_wp_enqueue_scripts() : void {
function register_blocks() : void {
register_block_type( ROOT_DIR . '/build/taxonomy' );
register_block_type( ROOT_DIR . '/build/post-type' );
+ register_block_type( ROOT_DIR . '/build/author' );
}
/**
@@ -83,8 +84,8 @@ function pre_get_posts_transpose_query_vars( WP_Query $query ) : void {
}
$prefix = $query->is_main_query() ? 'query-' : "query-{$query_id}-";
- $tax_query = [];
$valid_keys = [
+ 'author' => '',
'post_type' => $query->is_search() ? 'any' : 'post',
's' => '',
];
diff --git a/src/author/block.json b/src/author/block.json
new file mode 100644
index 0000000..decad72
--- /dev/null
+++ b/src/author/block.json
@@ -0,0 +1,61 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "query-filter/author",
+ "version": "0.1.0",
+ "title": "Author Filter",
+ "category": "theme",
+ "icon": "filter",
+ "description": "Allows users to filter by author when placed wihin a query loop block",
+ "ancestor": [ "core/query" ],
+ "usesContext": [ "queryId", "query" ],
+ "supports": {
+ "html": false,
+ "className": true,
+ "customClassName": true,
+ "color": {
+ "background": true,
+ "text": true
+ },
+ "typography": {
+ "fontSize": true,
+ "textAlign": true,
+ "lineHeight": true,
+ "__experimentalFontFamily": true,
+ "__experimentalFontWeight": true,
+ "__experimentalFontStyle": true,
+ "__experimentalTextTransform": true,
+ "__experimentalTextDecoration": true,
+ "__experimentalLetterSpacing": true,
+ "__experimentalDefaultControls": {
+ "fontSize": true
+ }
+ },
+ "spacing": {
+ "margin": true,
+ "padding": true,
+ "blockGap": true
+ },
+ "interactivity": {
+ "clientNavigation": true
+ }
+ },
+ "attributes": {
+ "emptyLabel": {
+ "type": "string",
+ "default": ""
+ },
+ "label": {
+ "type": "string"
+ },
+ "showLabel": {
+ "type": "boolean",
+ "default": true
+ }
+ },
+ "textdomain": "query-filter",
+ "editorScript": "file:./index.js",
+ "viewScriptModule": "query-filter-author-view-script-module",
+ "style": "query-filter-view",
+ "render": "file:./render.php"
+}
diff --git a/src/author/edit.js b/src/author/edit.js
new file mode 100644
index 0000000..984ee13
--- /dev/null
+++ b/src/author/edit.js
@@ -0,0 +1,58 @@
+import { __ } from '@wordpress/i18n';
+import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
+import { PanelBody, TextControl, ToggleControl } from '@wordpress/components';
+
+export default function Edit( { attributes, setAttributes } ) {
+ const { emptyLabel, label, showLabel } = attributes;
+
+ return (
+ <>
+
+
+ setAttributes( { label: newLabel } ) }
+ />
+
+ setAttributes( { showLabel: newShowLabel } )
+ }
+ />
+
+ setAttributes( { emptyLabel: newEmptyLabel } )
+ }
+ />
+
+
+
+ { showLabel && (
+
+ ) }
+
+
+ >
+ );
+}
diff --git a/src/author/index.js b/src/author/index.js
new file mode 100644
index 0000000..0157b8f
--- /dev/null
+++ b/src/author/index.js
@@ -0,0 +1,10 @@
+import { registerBlockType } from '@wordpress/blocks';
+import Edit from './edit';
+import metadata from './block.json';
+
+registerBlockType( metadata.name, {
+ /**
+ * @see ./edit.js
+ */
+ edit: Edit,
+} );
diff --git a/src/author/render.php b/src/author/render.php
new file mode 100644
index 0000000..c6bde90
--- /dev/null
+++ b/src/author/render.php
@@ -0,0 +1,86 @@
+context['query']['inherit'] ) {
+ $query_var = 'query-author'; // Changed from query-post_type
+ $page_var = 'page';
+ $base_url = str_replace( '/page/' . get_query_var( 'paged' ), '', remove_query_arg( [ $query_var, $page_var ] ) );
+} else {
+ $query_id = $block->context['queryId'] ?? 0;
+ $query_var = sprintf( 'query-%d-author', $query_id ); // Changed from query-%d-post_type
+ $page_var = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page';
+ $base_url = remove_query_arg( [ $query_var, $page_var ] );
+}
+
+// Determine relevant post types for filtering authors.
+$relevant_post_types = [];
+
+// Get post types from block context if they are explicitly set.
+if ( ! empty( $block->context['query']['postType'] ) ) {
+ $types = is_array( $block->context['query']['postType'] ) ? $block->context['query']['postType'] : explode( ',', $block->context['query']['postType'] );
+ $relevant_post_types = array_merge( $relevant_post_types, array_map( 'trim', $types ) );
+}
+
+// Support for enhanced query block (multiple_posts).
+if ( ! empty( $block->context['query']['multiple_posts'] ) && is_array( $block->context['query']['multiple_posts'] ) ) {
+ $relevant_post_types = array_merge( $relevant_post_types, $block->context['query']['multiple_posts'] );
+}
+
+// Handle inherited query.
+if ( $block->context['query']['inherit'] ) {
+ $main_query_post_type = $wp_query->get( 'post_type' );
+
+ if ( empty( $main_query_post_type ) || 'any' === $main_query_post_type ) {
+ // If main query is 'any' or not specific, consider all public, viewable post types.
+ $public_types = get_post_types( [ 'public' => true, 'show_ui' => true ], 'names' );
+ // Exclude 'attachment' by default, similar to how Query Loop block might treat 'any'.
+ if ( ! get_option( 'wp_attachment_pages_enabled' ) ) {
+ unset( $public_types['attachment'] );
+ }
+ $relevant_post_types = array_merge( $relevant_post_types, array_values( $public_types ) );
+ } else {
+ $relevant_post_types = array_merge( $relevant_post_types, (array) $main_query_post_type );
+ }
+}
+
+$relevant_post_types = array_values( array_unique( array_filter( $relevant_post_types ) ) );
+
+$user_args = [
+ 'capability' => [ 'publish_posts' ], // Users who can publish posts
+ 'fields' => [ 'ID', 'display_name' ],
+ 'orderby' => 'display_name',
+ 'order' => 'ASC',
+];
+
+// If specific post types are identified for the query, filter authors by those.
+// Otherwise, get authors who have published any post (adhering to 'authors' role).
+if ( ! empty( $relevant_post_types ) ) {
+ $user_args['has_published_posts'] = $relevant_post_types;
+} else {
+ // If $relevant_post_types is empty, it implies the query is for "any" post type.
+ // So, we list authors who have published any type of content.
+ // `get_users` with `who => 'authors'` covers users with publishing roles.
+ // Setting `has_published_posts = true` explicitly queries for posts in public post types.
+ $user_args['has_published_posts'] = true;
+}
+
+$authors = get_users( $user_args );
+
+if ( empty( $authors ) ) {
+ return;
+}
+?>
+
+ 'wp-block-query-filter' ] ); ?> data-wp-interactive="query-filter" data-wp-context="{}">
+
+
+