183 lines
5.4 KiB
Go
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"
|
|
)
|