What problem does this address?
Parent Issue: #3050 - Introduce support for the @OneOf GraphQL Directive
Summary
Replace the current id/idType argument pattern with semantic oneOf by arguments across all singular node queries. This provides better type safety, improved developer experience, and establishes oneOf patterns for future WPGraphQL features.
Current vs. Proposed
Current Pattern
# Error-prone - relies on resolver validation
post(id: "hello-world", idType: SLUG) { title }
user(id: "john@example.com", idType: EMAIL) { name }
category(id: 5, idType: DATABASE_ID) { name }
# Invalid combinations possible at schema level
post(id: "hello-world", idType: DATABASE_ID) { title } # Runtime error
Proposed Pattern
# Type-safe - schema validates input
post(by: { slug: "hello-world" }) { title }
user(by: { email: "john@example.com" }) { name }
category(by: { databaseId: 5 }) { name }
# Invalid combinations prevented at schema level
post(by: { slug: "hello-world", databaseId: 123 }) # Schema validation error
Scope
Affected Query Fields
- Posts:
post, page, and all custom post type singular queries
- Users:
user
- Terms:
category, tag, and all custom taxonomy term queries
- Media:
mediaItem
- Comments:
comment (if applicable)
Implementation Requirements
1. Create oneOf Identifier Input Types
"""Identify a post by one of several methods"""
input PostIdentifierInput @oneOf {
"""The globally unique ID"""
id: ID
"""The database ID"""
databaseId: Int
"""The URI/path"""
uri: String
"""The slug"""
slug: String
}
"""Identify a user by one of several methods"""
input UserIdentifierInput @oneOf {
"""The globally unique ID"""
id: ID
"""The database ID"""
databaseId: Int
"""The email address"""
email: String
"""The username/login"""
username: String
"""The user slug/nicename"""
slug: String
}
"""Identify a term by one of several methods"""
input TermIdentifierInput @oneOf {
"""The globally unique ID"""
id: ID
"""The database ID"""
databaseId: Int
"""The slug"""
slug: String
"""The name"""
name: String
}
"""Identify a media item by one of several methods"""
input MediaItemIdentifierInput @oneOf {
"""The globally unique ID"""
id: ID
"""The database ID"""
databaseId: Int
"""The source URL"""
sourceUrl: String
"""The slug"""
slug: String
}
2. Add by Arguments to Query Fields
type RootQuery {
# Existing (to be deprecated)
post(
id: ID! @deprecated(reason: "Use the 'by' argument instead")
idType: PostIdType @deprecated(reason: "Use the 'by' argument instead")
): Post
# New oneOf approach
post(by: PostIdentifierInput!): Post
# Apply same pattern to all affected fields
user(by: UserIdentifierInput!): User
category(by: TermIdentifierInput!): Category
mediaItem(by: MediaItemIdentifierInput!): MediaItem
# etc.
}
3. Validation and Error Handling
- Schema-level validation: oneOf directive prevents multiple identifier types
- Runtime validation: Throw error if both old and new patterns used together
- Resolver logic: Handle all identifier types in resolvers
// Example validation in resolver
if (!empty($args['id']) && !empty($args['by'])) {
throw new UserError(
'Cannot use deprecated "id" argument with new "by" argument. Please use only the "by" argument.'
);
}
Benefits
Developer Experience
- Intuitive: Clear semantic meaning vs. generic
id/idType
- Type-safe: Schema prevents invalid identifier combinations
- Discoverable: GraphQL introspection reveals available identifier types
- Self-documenting: Field names indicate what type of identifier is expected
Technical Benefits
- Better error messages: Schema validation provides specific feedback
- Reduced support burden: Fewer "how do I query by X?" questions
- Foundation for future: Establishes oneOf patterns for connection filtering
- Extensible: Plugin developers can add custom identifier types
Implementation Plan
Phase 1: Core Infrastructure
Phase 2: Schema Updates
Phase 3: Testing & Documentation
Phase 4: Extension Support
Backward Compatibility
Deprecation Strategy
- 12-18 month transition period with both patterns supported
- Deprecation warnings in schema introspection
- Clear migration guidance in documentation
- Runtime errors only when patterns are mixed
Migration Support
- Before/after examples for all common patterns
- Automated migration suggestions where possible
- Community education through blog posts and tutorials
Testing Requirements
Unit Tests
Integration Tests
Schema Tests
Success Metrics
Related Issues
Dependencies
What problem does this address?
Parent Issue: #3050 - Introduce support for the @OneOf GraphQL Directive
Summary
Replace the current
id/idTypeargument pattern with semantic oneOfbyarguments across all singular node queries. This provides better type safety, improved developer experience, and establishes oneOf patterns for future WPGraphQL features.Current vs. Proposed
Current Pattern
Proposed Pattern
Scope
Affected Query Fields
post,page, and all custom post type singular queriesusercategory,tag, and all custom taxonomy term queriesmediaItemcomment(if applicable)Implementation Requirements
1. Create oneOf Identifier Input Types
2. Add
byArguments to Query Fields3. Validation and Error Handling
Benefits
Developer Experience
id/idTypeTechnical Benefits
Implementation Plan
Phase 1: Core Infrastructure
byargumentsPhase 2: Schema Updates
byarguments to all affected query fieldsid/idTypeargumentsPhase 3: Testing & Documentation
Phase 4: Extension Support
Backward Compatibility
Deprecation Strategy
Migration Support
Testing Requirements
Unit Tests
idandidTypemust be used together (if using deprecated pattern)Integration Tests
Schema Tests
byfields for all affected queriesid/idTypefields marked correctlySuccess Metrics
Related Issues
filterarg across connections #1385 - Connection filtering (future oneOf opportunity)Dependencies