"""
Bulk Operations Schemas
Pydantic models for WordPress bulk operations including:
- Bulk updates for posts/products
- Bulk deletions
- Bulk category/tag assignments
"""
from typing import Any
from pydantic import BaseModel, Field, field_validator
class BulkUpdatePostsParams(BaseModel):
"""Parameters for bulk updating posts"""
post_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post IDs to update (max 100)"
)
updates: dict[str, Any] = Field(
..., description="Fields to update (status, author_id, categories, tags, etc.)"
)
@classmethod
@field_validator("post_ids")
def validate_post_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All post IDs must be positive integers")
return v
@classmethod
@field_validator("updates")
def validate_updates(cls, v):
"""Validate update fields are allowed"""
allowed_fields = {
"status",
"title",
"content",
"excerpt",
"author",
"categories",
"tags",
"featured_media",
"comment_status",
"ping_status",
"sticky",
"format",
"meta",
}
invalid_fields = set(v.keys()) - allowed_fields
if invalid_fields:
raise ValueError(f"Invalid update fields: {', '.join(invalid_fields)}")
return v
class BulkDeletePostsParams(BaseModel):
"""Parameters for bulk deleting posts"""
post_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post IDs to delete (max 100)"
)
force: bool = Field(default=False, description="Force permanent deletion (bypass trash)")
@classmethod
@field_validator("post_ids")
def validate_post_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All post IDs must be positive integers")
return v
class BulkUpdateProductsParams(BaseModel):
"""Parameters for bulk updating WooCommerce products"""
product_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of product IDs to update (max 100)"
)
updates: dict[str, Any] = Field(
..., description="Fields to update (price, stock_quantity, status, etc.)"
)
@classmethod
@field_validator("product_ids")
def validate_product_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All product IDs must be positive integers")
return v
@classmethod
@field_validator("updates")
def validate_updates(cls, v):
"""Validate update fields are allowed"""
allowed_fields = {
"name",
"status",
"featured",
"catalog_visibility",
"description",
"short_description",
"sku",
"price",
"regular_price",
"sale_price",
"stock_quantity",
"stock_status",
"manage_stock",
"categories",
"tags",
"images",
"attributes",
"meta_data",
}
invalid_fields = set(v.keys()) - allowed_fields
if invalid_fields:
raise ValueError(f"Invalid update fields: {', '.join(invalid_fields)}")
return v
class BulkDeleteProductsParams(BaseModel):
"""Parameters for bulk deleting products"""
product_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of product IDs to delete (max 100)"
)
force: bool = Field(default=False, description="Force permanent deletion")
@classmethod
@field_validator("product_ids")
def validate_product_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All product IDs must be positive integers")
return v
class BulkAssignCategoriesParams(BaseModel):
"""Parameters for bulk assigning categories"""
item_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post/product IDs (max 100)"
)
category_ids: list[int] = Field(..., min_length=1, description="List of category IDs to assign")
replace: bool = Field(
default=False, description="Replace existing categories (true) or append (false)"
)
item_type: str = Field(default="post", description="Type of items: 'post' or 'product'")
@classmethod
@field_validator("item_ids", "category_ids")
def validate_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All IDs must be positive integers")
return v
@classmethod
@field_validator("item_type")
def validate_item_type(cls, v):
"""Validate item type"""
if v not in ["post", "product"]:
raise ValueError("item_type must be 'post' or 'product'")
return v
class BulkAssignTagsParams(BaseModel):
"""Parameters for bulk assigning tags"""
item_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of post/product IDs (max 100)"
)
tag_ids: list[int] = Field(..., min_length=1, description="List of tag IDs to assign")
replace: bool = Field(
default=False, description="Replace existing tags (true) or append (false)"
)
item_type: str = Field(default="post", description="Type of items: 'post' or 'product'")
@classmethod
@field_validator("item_ids", "tag_ids")
def validate_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All IDs must be positive integers")
return v
@classmethod
@field_validator("item_type")
def validate_item_type(cls, v):
"""Validate item type"""
if v not in ["post", "product"]:
raise ValueError("item_type must be 'post' or 'product'")
return v
class BulkUpdateMediaParams(BaseModel):
"""Parameters for bulk updating media items"""
media_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of media IDs to update (max 100)"
)
updates: dict[str, Any] = Field(
..., description="Fields to update (alt_text, title, caption, description)"
)
@classmethod
@field_validator("media_ids")
def validate_media_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All media IDs must be positive integers")
return v
@classmethod
@field_validator("updates")
def validate_updates(cls, v):
"""Validate update fields are allowed"""
allowed_fields = {"title", "alt_text", "caption", "description", "meta"}
invalid_fields = set(v.keys()) - allowed_fields
if invalid_fields:
raise ValueError(f"Invalid update fields: {', '.join(invalid_fields)}")
return v
class BulkDeleteMediaParams(BaseModel):
"""Parameters for bulk deleting media items"""
media_ids: list[int] = Field(
..., min_length=1, max_length=100, description="List of media IDs to delete (max 100)"
)
force: bool = Field(
default=True, description="Force permanent deletion (media can't be trashed)"
)
@classmethod
@field_validator("media_ids")
def validate_media_ids(cls, v):
"""Ensure all IDs are positive"""
if any(id <= 0 for id in v):
raise ValueError("All media IDs must be positive integers")
return v
class BulkOperationResult(BaseModel):
"""Result of a bulk operation"""
success_count: int = Field(description="Number of successful operations")
failed_count: int = Field(description="Number of failed operations")
total: int = Field(description="Total items processed")
failed_ids: list[int] = Field(default=[], description="IDs that failed to process")
errors: list[dict[str, Any]] = Field(default=[], description="Detailed error information")