[ 'required' => ['@type', 'headline', 'author', 'datePublished'], 'recommended' => ['description', 'image', 'dateModified', 'publisher', 'mainEntityOfPage'], 'optional' => ['wordCount', 'keywords', 'articleSection', 'articleBody'] ], 'BlogPosting' => [ 'required' => ['@type', 'headline', 'author', 'datePublished'], 'recommended' => ['description', 'image', 'dateModified', 'publisher', 'mainEntityOfPage'], 'optional' => ['wordCount', 'keywords', 'blogPost', 'comment'] ], 'TechnicalArticle' => [ 'required' => ['@type', 'headline', 'author', 'datePublished'], 'recommended' => ['description', 'image', 'dateModified', 'publisher', 'mainEntityOfPage'], 'optional' => ['wordCount', 'keywords', 'articleSection', 'articleBody', 'dependencies', 'proficiencyLevel'] ], 'NewsArticle' => [ 'required' => ['@type', 'headline', 'author', 'datePublished'], 'recommended' => ['description', 'image', 'dateModified', 'publisher', 'mainEntityOfPage'], 'optional' => ['wordCount', 'keywords', 'articleSection', 'articleBody', 'dateline', 'printColumn', 'printEdition', 'printPage', 'printSection'] ], 'ScholarlyArticle' => [ 'required' => ['@type', 'headline', 'author', 'datePublished'], 'recommended' => ['description', 'image', 'dateModified', 'publisher', 'mainEntityOfPage'], 'optional' => ['wordCount', 'keywords', 'articleSection', 'articleBody', 'citation', 'pageStart', 'pageEnd', 'pagination'] ], 'Report' => [ 'required' => ['@type', 'headline', 'author', 'datePublished'], 'recommended' => ['description', 'image', 'dateModified', 'publisher', 'mainEntityOfPage'], 'optional' => ['wordCount', 'keywords', 'articleSection', 'articleBody', 'reportNumber'] ], 'Product' => [ 'required' => ['@type', 'name', 'description'], 'recommended' => ['image', 'offers', 'brand', 'sku', 'gtin', 'review', 'aggregateRating'], 'optional' => ['category', 'manufacturer', 'mpn', 'productID'] ], 'Organization' => [ 'required' => ['@type', 'name', 'url'], 'recommended' => ['logo', 'contactPoint', 'sameAs', 'address'], 'optional' => ['founder', 'foundingDate', 'description'] ], 'WebSite' => [ 'required' => ['@type', 'name', 'url'], 'recommended' => ['description', 'author', 'publisher', 'potentialAction'], 'optional' => ['sameAs', 'inLanguage'] ], 'FAQPage' => [ 'required' => ['@type', 'mainEntity'], 'recommended' => ['about', 'author'], 'optional' => ['name', 'description', 'url', 'dateModified'] ], // The WebPage family. Schema_Builder has had a `case 'WebPage'` branch // all along, but nothing here declared the type — so build_schema() // rejected it before the switch was ever reached, and that branch was // dead code. A customer asking for AboutPage and ContactPage is what // surfaced it (#624). // // Only the four the output side can actually emit as themselves. // ItemPage, QAPage and CollectionPage appear in // Schema_Graph::PAGE_LEVEL_TYPES but have no branch in // Global_SEO_Schema_Output::generate_schema(), so they fall to its // `default` arm and publish plain WebPage — offering a type that // silently emits a different one is worse than not offering it. 'WebPage' => [ 'required' => ['@type', 'name'], 'recommended' => ['description', 'url', 'datePublished', 'dateModified'], 'optional' => ['image', 'breadcrumb', 'primaryImageOfPage', 'about', 'mainEntity'] ], 'AboutPage' => [ 'required' => ['@type', 'name'], 'recommended' => ['description', 'url', 'datePublished', 'dateModified'], 'optional' => ['image', 'breadcrumb', 'primaryImageOfPage', 'about', 'mainEntity'] ], 'ContactPage' => [ 'required' => ['@type', 'name'], 'recommended' => ['description', 'url', 'datePublished', 'dateModified'], 'optional' => ['image', 'breadcrumb', 'primaryImageOfPage', 'about', 'mainEntity'] ], 'ProfilePage' => [ 'required' => ['@type', 'name'], 'recommended' => ['description', 'url', 'datePublished', 'dateModified'], 'optional' => ['image', 'breadcrumb', 'primaryImageOfPage', 'about', 'mainEntity'] ], 'LocalBusiness' => [ 'required' => ['@type', 'name', 'address'], 'recommended' => ['telephone', 'url', 'openingHours', 'geo', 'priceRange'], 'optional' => ['description', 'logo', 'contactPoint', 'sameAs', 'paymentAccepted', 'currenciesAccepted'] ], 'Person' => [ 'required' => ['@type', 'name'], 'recommended' => ['url', 'image'], 'optional' => ['jobTitle', 'worksFor', 'sameAs', 'description'] ], 'SoftwareApplication' => [ 'required' => ['@type', 'name', 'applicationCategory'], 'recommended' => ['description', 'url', 'offers', 'creator', 'features', 'aggregateRating'], 'optional' => ['alternateName', 'version', 'operatingSystem', 'fileSize', 'license', 'downloadUrl', 'screenshot'] ], 'Event' => [ 'required' => ['@type', 'name', 'startDate', 'location'], 'recommended' => ['endDate', 'description', 'image', 'offers', 'performer'], 'optional' => ['eventStatus', 'eventAttendanceMode', 'url', 'organizer'] ], 'Review' => [ 'required' => ['@type', 'itemReviewed', 'reviewRating', 'author'], 'recommended' => ['reviewBody', 'datePublished', 'publisher'], 'optional' => ['name', 'url'] ], 'HowTo' => [ 'required' => ['@type', 'name', 'step'], 'recommended' => ['image', 'totalTime', 'estimatedCost', 'tool', 'supply'], 'optional' => ['description', 'prepTime', 'difficulty', 'yield', 'video'] ], 'VideoObject' => [ 'required' => ['@type', 'name', 'description', 'thumbnailUrl', 'uploadDate'], 'recommended' => ['contentUrl', 'embedUrl', 'duration'], 'optional' => ['interactionStatistic', 'expires', 'regionsAllowed'] ] ]; /** * Schema.org context URL * PRESERVED: Exact same value from original Schema_Generator * * @since 1.0.0 * @var string */ private string $schema_context = 'https://schema.org'; /** * Get all supported schema types * Simplified: Context filtering moved to config files * * @since 1.0.0 * * @return array Array of all supported schema types */ public function get_all_supported_types(): array { return array_keys($this->supported_schema_types); } /** * Check if schema type is supported * PRESERVED: Exact same method logic from original Schema_Generator * * @since 1.0.0 * * @param string $schema_type Schema type to check * @return bool True if supported, false otherwise */ public function is_supported_schema_type(string $schema_type): bool { return isset($this->supported_schema_types[$schema_type]); } /** * Get schema type specification * PRESERVED: Returns exact same data structure as original Schema_Generator * * @since 1.0.0 * * @param string $schema_type Schema type * @return array Schema type specification */ public function get_schema_specification(string $schema_type): array { return $this->supported_schema_types[$schema_type] ?? []; } /** * Normalize schema type name to proper Schema.org format * * @since 1.0.0 * * @param string $schema_type Schema type to normalize * @return string Normalized schema type */ public function normalize_schema_type(string $schema_type): string { // Handle Schema.org camelCase requirements $schema_cases = [ 'localbusiness' => 'LocalBusiness', 'softwareapplication' => 'SoftwareApplication', 'blogposting' => 'BlogPosting', 'technicalarticle' => 'TechnicalArticle', 'newsarticle' => 'NewsArticle', 'scholarlyarticle' => 'ScholarlyArticle', 'faqpage' => 'FAQPage', 'howto' => 'HowTo', 'videoobject' => 'VideoObject' ]; $key = strtolower($schema_type); return $schema_cases[$key] ?? ucfirst($schema_type); } /** * Create base schema structure * PRESERVED: Exact same method logic from original Schema_Generator * * @since 1.0.0 * * @param string $schema_type Schema type * @return array Base schema structure */ public function create_base_schema(string $schema_type): array { return [ '@context' => $this->schema_context, '@type' => $schema_type ]; } // Removed error schema creation - moved to Schema_Builder where it belongs // Removed auto-detection logic - over-engineered and rarely used // Schema types are now explicitly selected by users /** * Get schema context URL * PRESERVED: Returns exact same value as original Schema_Generator * * @since 1.0.0 * * @return string Schema context URL */ public function get_schema_context(): string { return $this->schema_context; } /** * Get all supported schema types * PRESERVED: Returns exact same data structure as original Schema_Generator * * @since 1.0.0 * * @return array All supported schema types with specifications */ public function get_all_schema_types(): array { return $this->supported_schema_types; } }