Files
WPSidekick/internal/wordpress/models.go
T
2026-01-25 08:57:55 +01:00

183 lines
5.4 KiB
Go

package wordpress
import (
"encoding/json"
"strings"
"time"
)
// WPTime handles WordPress time formats that may omit timezone.
type WPTime struct {
time.Time
}
func (t *WPTime) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
if s == "" {
t.Time = time.Time{}
return nil
}
s = strings.TrimSpace(s)
layouts := []string{
time.RFC3339,
"2006-01-02T15:04:05",
"2006-01-02 15:04:05",
}
var lastErr error
for _, layout := range layouts {
parsed, err := time.Parse(layout, s)
if err == nil {
t.Time = parsed
return nil
}
lastErr = err
}
return lastErr
}
// Post represents a WordPress post from the REST API
type Post struct {
ID int `json:"id"`
Date WPTime `json:"date"`
Modified WPTime `json:"modified"`
Slug string `json:"slug"`
Status string `json:"status"`
Type string `json:"type"`
Link string `json:"link"`
Title Rendered `json:"title"`
Content Rendered `json:"content"`
Excerpt Rendered `json:"excerpt"`
Author int `json:"author"`
// FeaturedMedia represents the featured image ID
FeaturedMedia int `json:"featured_media"`
// CommentStatus indicates if comments are allowed
CommentStatus string `json:"comment_status"`
// PingStatus indicates if pingbacks are allowed
PingStatus string `json:"ping_status"`
// Sticky indicates if the post is sticky
Sticky bool `json:"sticky"`
Format string `json:"format"`
Categories []int `json:"categories"`
Tags []int `json:"tags"`
// Meta holds custom meta fields
Meta map[string]interface{} `json:"meta"`
// Lang holds the Polylang language code (en, es, etc.)
Lang string `json:"lang,omitempty"`
}
// Rendered represents a WordPress rendered field (title, content, excerpt)
type Rendered struct {
Rendered string `json:"rendered"`
Raw string `json:"raw,omitempty"`
}
// Category represents a WordPress category
type Category struct {
ID int `json:"id"`
Count int `json:"count"`
Description string `json:"description"`
Link string `json:"link"`
Name string `json:"name"`
Slug string `json:"slug"`
Taxonomy string `json:"taxonomy"`
Parent int `json:"parent"`
}
// Tag represents a WordPress tag
type Tag struct {
ID int `json:"id"`
Count int `json:"count"`
Description string `json:"description"`
Link string `json:"link"`
Name string `json:"name"`
Slug string `json:"slug"`
Taxonomy string `json:"taxonomy"`
}
// PostUpdate represents the fields to update when creating a draft revision
type PostUpdate struct {
// Status should be "draft" for revisions pending approval
Status string `json:"status"`
Title string `json:"title,omitempty"`
Content string `json:"content,omitempty"`
Excerpt string `json:"excerpt,omitempty"`
// Meta holds SEO meta fields and optimization metadata
Meta map[string]interface{} `json:"meta,omitempty"`
}
// ListParams represents parameters for listing posts
type ListParams struct {
// Lang is the Polylang language code (en, es, etc.)
Lang string
// Status filters by post status (publish, draft, pending, etc.)
Status string
// OrderBy specifies the field to order by (modified, date, title, etc.)
OrderBy string
// Order specifies the order direction (asc, desc)
Order string
// PerPage specifies the number of posts per page (default: 10, max: 100)
PerPage int
// Page specifies the page number
Page int
// After filters posts modified after this date
After *time.Time
// Before filters posts modified before this date
Before *time.Time
// Search filters posts by search term
Search string
// Categories filters by category IDs
Categories []int
// Tags filters by tag IDs
Tags []int
}
// InternalPostReference represents a simplified post reference for internal linking
type InternalPostReference struct {
ID int `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
Link string `json:"link"`
Categories []int `json:"categories"`
Tags []int `json:"tags"`
Excerpt string `json:"excerpt"`
}
// SelectionCriteria represents criteria for selecting posts to optimize
type SelectionCriteria struct {
// Language is the Polylang language code
Language string
// MinContentLength is the minimum word count (in words)
MinContentLength int
// MinAgeDays only considers posts older than this many days (to avoid very recent posts)
MinAgeDays int
// MaxAgeDays only considers posts not older than this many days
MaxAgeDays int
// CooldownDays don't re-optimize posts for this many days
CooldownDays int
// ExcludeCategories optionally excludes specific category IDs
ExcludeCategories []int
}
// MetaFields represents common WordPress SEO meta field names
// These work with both Yoast SEO and RankMath
const (
// SEO meta fields (RankMath)
MetaRankMathTitle = "rank_math_title"
MetaRankMathDescription = "rank_math_description"
MetaRankMathFocusKW = "rank_math_focus_keyword"
// SEO meta fields (Yoast)
MetaYoastTitle = "_yoast_wpseo_title"
MetaYoastDescription = "_yoast_wpseo_metadesc"
MetaYoastFocusKW = "_yoast_wpseo_focuskw"
// Custom meta fields for optimization tracking
MetaSEOOptimizedAt = "_seo_optimized_at"
MetaSEOOptimizationData = "_seo_optimization_data"
MetaSEOOptimizationSummary = "_seo_optimization_summary"
MetaDraftOfPostID = "_draft_of_post_id"
)