tigerstyle-heat/includes/modules/class-structured-data.php
Ryan Malloy 0028738e33 Initial commit: TigerStyle Heat v2.0.0
Make your WordPress site irresistible. Natural SEO attraction with:
- robots.txt management
- sitemap.xml generation
- LLMs.txt support
- Google integration (Analytics, Search Console, Tag Manager)
- Schema.org structured data
- Open Graph / Twitter Card meta tags
- AMP support
- Visual elements gallery
- Built-in backup/restore module

Includes build.sh and .distignore for WordPress-installable release ZIPs.
2026-05-27 13:41:35 -06:00

3059 lines
119 KiB
PHP

<?php
/**
* Structured Data Module for TigerStyle Heat
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
class TigerStyleSEO_StructuredData {
/**
* Single instance
*/
private static $instance = null;
/**
* Get instance
*/
public static function instance() {
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
$this->init();
}
/**
* Initialize the module
*/
private function init() {
// Frontend hooks
add_action('wp_head', array($this, 'inject_structured_data'), 2);
// Admin hooks
if (is_admin()) {
add_action('admin_post_update_google_appearance', array($this, 'handle_form_submission'));
add_action('wp_ajax_seo_health_check', array($this, 'handle_ajax_request'));
}
}
/**
* Inject structured data into head section
*/
public function inject_structured_data() {
$structured_data = array();
// Organization structured data
if (TigerStyleSEO_Utils::get_option('organization_enabled', false)) {
$organization_data = $this->get_organization_schema();
if (!empty($organization_data)) {
$structured_data[] = $organization_data;
}
}
// Local Business structured data
if (TigerStyleSEO_Utils::get_option('local_business_enabled', false)) {
$business_data = $this->get_local_business_schema();
if (!empty($business_data)) {
$structured_data[] = $business_data;
}
}
// Return Policy structured data
$return_policy_data = $this->get_return_policy_schema();
if (!empty($return_policy_data)) {
$structured_data[] = $return_policy_data;
}
// Profile Page structured data
$profile_data = $this->get_profile_page_schema();
if (!empty($profile_data)) {
$structured_data[] = $profile_data;
}
// QAPage structured data
$qa_data = $this->get_qapage_schema();
if (!empty($qa_data)) {
$structured_data[] = $qa_data;
}
// Speakable structured data
$speakable_data = $this->get_speakable_schema();
if (!empty($speakable_data)) {
$structured_data[] = $speakable_data;
}
// Video structured data
$video_data = $this->get_video_schema();
if (!empty($video_data)) {
$structured_data[] = $video_data;
}
// Image structured data
$image_data = $this->get_image_schema();
if (!empty($image_data)) {
$structured_data = array_merge($structured_data, $image_data);
}
// Product structured data
$product_data = $this->get_product_schema();
if (!empty($product_data)) {
$structured_data[] = $product_data;
}
// Article structured data
$article_data = $this->get_article_schema();
if (!empty($article_data)) {
$structured_data[] = $article_data;
}
// Output JSON-LD structured data
if (!empty($structured_data)) {
echo "\n<!-- TigerStyle Heat Structured Data -->\n";
foreach ($structured_data as $schema) {
echo '<script type="application/ld+json">';
echo wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
echo '</script>' . "\n";
}
echo "<!-- /TigerStyle Heat Structured Data -->\n";
}
// Output Google Site Verification meta tag
$this->output_google_verification();
}
/**
* Output Google Site Verification meta tag
*/
private function output_google_verification() {
$verification_method = TigerStyleSEO_Utils::get_option('google_verification_method', '');
$verification_code = TigerStyleSEO_Utils::get_option('google_verification_code', '');
// Only output meta tag if method is set to meta_tag and code is provided
if ($verification_method === 'meta_tag' && !empty($verification_code)) {
// Sanitize the verification code (should only contain alphanumeric characters, hyphens, and underscores)
$sanitized_code = preg_replace('/[^a-zA-Z0-9_-]/', '', $verification_code);
if (!empty($sanitized_code)) {
echo "\n<!-- Google Site Verification -->\n";
echo '<meta name="google-site-verification" content="' . esc_attr($sanitized_code) . '" />' . "\n";
echo "<!-- /Google Site Verification -->\n";
}
}
}
/**
* Handle form submission
*/
public function handle_form_submission() {
// Verify nonce
if (!TigerStyleSEO_Utils::verify_nonce('google_appearance_nonce', 'update_google_appearance')) {
wp_die(__('Security check failed.', 'tigerstyle-heat'));
}
// Check user capabilities
if (!TigerStyleSEO_Utils::current_user_can_manage()) {
wp_die(__('You do not have sufficient permissions to access this page.', 'tigerstyle-heat'));
}
try {
// Save organization settings
TigerStyleSEO_Utils::update_option('organization_enabled', isset($_POST['organization_enabled']) && $_POST['organization_enabled'] === '1');
TigerStyleSEO_Utils::update_option('organization_name', sanitize_text_field($_POST['organization_name']));
TigerStyleSEO_Utils::update_option('organization_logo', esc_url_raw($_POST['organization_logo']));
TigerStyleSEO_Utils::update_option('organization_description', sanitize_textarea_field($_POST['organization_description']));
TigerStyleSEO_Utils::update_option('organization_email', sanitize_email($_POST['organization_email']));
TigerStyleSEO_Utils::update_option('organization_phone', sanitize_text_field($_POST['organization_phone']));
TigerStyleSEO_Utils::update_option('organization_social_profiles', sanitize_textarea_field($_POST['organization_social_profiles']));
// Save local business settings
TigerStyleSEO_Utils::update_option('local_business_enabled', isset($_POST['local_business_enabled']) && $_POST['local_business_enabled'] === '1');
TigerStyleSEO_Utils::update_option('business_type', sanitize_text_field($_POST['business_type']));
TigerStyleSEO_Utils::update_option('business_address_street', sanitize_text_field($_POST['business_address_street']));
TigerStyleSEO_Utils::update_option('business_address_city', sanitize_text_field($_POST['business_address_city']));
TigerStyleSEO_Utils::update_option('business_address_state', sanitize_text_field($_POST['business_address_state']));
TigerStyleSEO_Utils::update_option('business_address_zip', sanitize_text_field($_POST['business_address_zip']));
TigerStyleSEO_Utils::update_option('business_address_country', sanitize_text_field($_POST['business_address_country']));
TigerStyleSEO_Utils::update_option('business_latitude', floatval($_POST['business_latitude']));
TigerStyleSEO_Utils::update_option('business_longitude', floatval($_POST['business_longitude']));
TigerStyleSEO_Utils::update_option('business_hours', sanitize_textarea_field($_POST['business_hours']));
TigerStyleSEO_Utils::update_option('business_price_range', sanitize_text_field($_POST['business_price_range']));
// Save return policy settings
TigerStyleSEO_Utils::update_option('return_policy_enabled', isset($_POST['return_policy_enabled']) && $_POST['return_policy_enabled'] === '1');
TigerStyleSEO_Utils::update_option('return_policy_type', sanitize_text_field($_POST['return_policy_type']));
TigerStyleSEO_Utils::update_option('return_policy_category', sanitize_text_field($_POST['return_policy_category']));
TigerStyleSEO_Utils::update_option('return_policy_days', intval($_POST['return_policy_days']));
TigerStyleSEO_Utils::update_option('return_policy_url', esc_url_raw($_POST['return_policy_url']));
TigerStyleSEO_Utils::update_option('return_policy_country', sanitize_text_field($_POST['return_policy_country']));
TigerStyleSEO_Utils::update_option('return_policy_currency', sanitize_text_field($_POST['return_policy_currency']));
TigerStyleSEO_Utils::update_option('customer_remorse_return_fees', floatval($_POST['customer_remorse_return_fees']));
TigerStyleSEO_Utils::update_option('item_defect_return_fees', floatval($_POST['item_defect_return_fees']));
TigerStyleSEO_Utils::update_option('restocking_fee', floatval($_POST['restocking_fee']));
// Save profile page settings
TigerStyleSEO_Utils::update_option('profile_page_enabled', isset($_POST['profile_page_enabled']) && $_POST['profile_page_enabled'] === '1');
TigerStyleSEO_Utils::update_option('profile_use_page_specific', isset($_POST['profile_use_page_specific']) && $_POST['profile_use_page_specific'] === '1');
TigerStyleSEO_Utils::update_option('profile_show_author_email', isset($_POST['profile_show_author_email']) && $_POST['profile_show_author_email'] === '1');
TigerStyleSEO_Utils::update_option('profile_person_name', sanitize_text_field($_POST['profile_person_name']));
TigerStyleSEO_Utils::update_option('profile_job_title', sanitize_text_field($_POST['profile_job_title']));
TigerStyleSEO_Utils::update_option('profile_description', sanitize_textarea_field($_POST['profile_description']));
TigerStyleSEO_Utils::update_option('profile_email', sanitize_email($_POST['profile_email']));
TigerStyleSEO_Utils::update_option('profile_phone', sanitize_text_field($_POST['profile_phone']));
TigerStyleSEO_Utils::update_option('profile_website', esc_url_raw($_POST['profile_website']));
TigerStyleSEO_Utils::update_option('profile_image', esc_url_raw($_POST['profile_image']));
TigerStyleSEO_Utils::update_option('profile_address_street', sanitize_text_field($_POST['profile_address_street']));
TigerStyleSEO_Utils::update_option('profile_address_city', sanitize_text_field($_POST['profile_address_city']));
TigerStyleSEO_Utils::update_option('profile_address_region', sanitize_text_field($_POST['profile_address_region']));
TigerStyleSEO_Utils::update_option('profile_address_postal_code', sanitize_text_field($_POST['profile_address_postal_code']));
TigerStyleSEO_Utils::update_option('profile_address_country', sanitize_text_field($_POST['profile_address_country']));
TigerStyleSEO_Utils::update_option('profile_social_profiles', sanitize_textarea_field($_POST['profile_social_profiles']));
TigerStyleSEO_Utils::update_option('profile_organization', sanitize_text_field($_POST['profile_organization']));
TigerStyleSEO_Utils::update_option('profile_colleagues', sanitize_textarea_field($_POST['profile_colleagues']));
// Save QAPage settings
TigerStyleSEO_Utils::update_option('qapage_enabled', isset($_POST['qapage_enabled']) && $_POST['qapage_enabled'] === '1');
TigerStyleSEO_Utils::update_option('qapage_auto_detect', isset($_POST['qapage_auto_detect']) && $_POST['qapage_auto_detect'] === '1');
TigerStyleSEO_Utils::update_option('qapage_manual_enable', isset($_POST['qapage_manual_enable']) && $_POST['qapage_manual_enable'] === '1');
TigerStyleSEO_Utils::update_option('qapage_auto_extract', isset($_POST['qapage_auto_extract']) && $_POST['qapage_auto_extract'] === '1');
TigerStyleSEO_Utils::update_option('qapage_question_text', sanitize_textarea_field($_POST['qapage_question_text']));
TigerStyleSEO_Utils::update_option('qapage_answer_text', sanitize_textarea_field($_POST['qapage_answer_text']));
// Save Speakable settings
TigerStyleSEO_Utils::update_option('speakable_enabled', isset($_POST['speakable_enabled']) && $_POST['speakable_enabled'] === '1');
TigerStyleSEO_Utils::update_option('speakable_auto_detect', isset($_POST['speakable_auto_detect']) && $_POST['speakable_auto_detect'] === '1');
TigerStyleSEO_Utils::update_option('speakable_include_headings', isset($_POST['speakable_include_headings']) && $_POST['speakable_include_headings'] === '1');
TigerStyleSEO_Utils::update_option('speakable_include_summary', isset($_POST['speakable_include_summary']) && $_POST['speakable_include_summary'] === '1');
TigerStyleSEO_Utils::update_option('speakable_include_content', isset($_POST['speakable_include_content']) && $_POST['speakable_include_content'] === '1');
TigerStyleSEO_Utils::update_option('speakable_include_navigation', isset($_POST['speakable_include_navigation']) && $_POST['speakable_include_navigation'] === '1');
TigerStyleSEO_Utils::update_option('speakable_css_selectors', sanitize_textarea_field($_POST['speakable_css_selectors']));
TigerStyleSEO_Utils::update_option('speakable_xpath_expressions', sanitize_textarea_field($_POST['speakable_xpath_expressions']));
// Save Video settings
TigerStyleSEO_Utils::update_option('video_enabled', isset($_POST['video_enabled']) && $_POST['video_enabled'] === '1');
TigerStyleSEO_Utils::update_option('video_custom_title', sanitize_text_field($_POST['video_custom_title']));
TigerStyleSEO_Utils::update_option('video_description', sanitize_textarea_field($_POST['video_description']));
TigerStyleSEO_Utils::update_option('video_url', esc_url_raw($_POST['video_url']));
TigerStyleSEO_Utils::update_option('video_thumbnail', esc_url_raw($_POST['video_thumbnail']));
TigerStyleSEO_Utils::update_option('video_duration', sanitize_text_field($_POST['video_duration']));
TigerStyleSEO_Utils::update_option('video_upload_date', sanitize_text_field($_POST['video_upload_date']));
TigerStyleSEO_Utils::update_option('video_quality', sanitize_text_field($_POST['video_quality']));
TigerStyleSEO_Utils::update_option('video_width', intval($_POST['video_width']));
TigerStyleSEO_Utils::update_option('video_height', intval($_POST['video_height']));
TigerStyleSEO_Utils::update_option('video_genre', sanitize_text_field($_POST['video_genre']));
TigerStyleSEO_Utils::update_option('video_director', sanitize_text_field($_POST['video_director']));
TigerStyleSEO_Utils::update_option('video_actors', sanitize_text_field($_POST['video_actors']));
TigerStyleSEO_Utils::update_option('video_music_by', sanitize_text_field($_POST['video_music_by']));
TigerStyleSEO_Utils::update_option('video_production_company', sanitize_text_field($_POST['video_production_company']));
TigerStyleSEO_Utils::update_option('video_transcript', sanitize_textarea_field($_POST['video_transcript']));
TigerStyleSEO_Utils::update_option('video_captions', esc_url_raw($_POST['video_captions']));
TigerStyleSEO_Utils::update_option('video_content_rating', sanitize_text_field($_POST['video_content_rating']));
// Save Image Metadata settings
TigerStyleSEO_Utils::update_option('imageobject_enabled', isset($_POST['imageobject_enabled']) && $_POST['imageobject_enabled'] === '1');
TigerStyleSEO_Utils::update_option('imageobject_include_featured', isset($_POST['imageobject_include_featured']) && $_POST['imageobject_include_featured'] === '1');
TigerStyleSEO_Utils::update_option('imageobject_include_content', isset($_POST['imageobject_include_content']) && $_POST['imageobject_include_content'] === '1');
TigerStyleSEO_Utils::update_option('imageobject_include_galleries', isset($_POST['imageobject_include_galleries']) && $_POST['imageobject_include_galleries'] === '1');
TigerStyleSEO_Utils::update_option('imageobject_include_exif', isset($_POST['imageobject_include_exif']) && $_POST['imageobject_include_exif'] === '1');
TigerStyleSEO_Utils::update_option('imageobject_include_location', isset($_POST['imageobject_include_location']) && $_POST['imageobject_include_location'] === '1');
TigerStyleSEO_Utils::update_option('imageobject_max_per_page', intval($_POST['imageobject_max_per_page']));
TigerStyleSEO_Utils::update_option('imageobject_prioritize_featured', isset($_POST['imageobject_prioritize_featured']) && $_POST['imageobject_prioritize_featured'] === '1');
TigerStyleSEO_Utils::update_option('imageobject_min_width', intval($_POST['imageobject_min_width']));
TigerStyleSEO_Utils::update_option('imageobject_min_height', intval($_POST['imageobject_min_height']));
TigerStyleSEO_Utils::update_option('imageobject_default_copyright_holder', sanitize_text_field($_POST['imageobject_default_copyright_holder']));
// Handle license selection
$license_value = sanitize_text_field($_POST['imageobject_default_license']);
if ($license_value === 'custom') {
$custom_license = esc_url_raw($_POST['imageobject_custom_license_url']);
TigerStyleSEO_Utils::update_option('imageobject_default_license', $custom_license);
} else {
TigerStyleSEO_Utils::update_option('imageobject_default_license', $license_value);
}
TigerStyleSEO_Utils::update_option('imageobject_custom_license_url', esc_url_raw($_POST['imageobject_custom_license_url']));
TigerStyleSEO_Utils::update_option('imageobject_default_author', sanitize_text_field($_POST['imageobject_default_author']));
// Save Product settings
TigerStyleSEO_Utils::update_option('product_enabled', isset($_POST['product_enabled']) && $_POST['product_enabled'] === '1');
TigerStyleSEO_Utils::update_option('product_auto_detect', isset($_POST['product_auto_detect']) && $_POST['product_auto_detect'] === '1');
TigerStyleSEO_Utils::update_option('product_manual_enable', isset($_POST['product_manual_enable']) && $_POST['product_manual_enable'] === '1');
// Basic product information
TigerStyleSEO_Utils::update_option('product_name', sanitize_text_field($_POST['product_name']));
TigerStyleSEO_Utils::update_option('product_description', sanitize_textarea_field($_POST['product_description']));
TigerStyleSEO_Utils::update_option('product_category', sanitize_text_field($_POST['product_category']));
// Product identifiers
TigerStyleSEO_Utils::update_option('product_sku', sanitize_text_field($_POST['product_sku']));
TigerStyleSEO_Utils::update_option('product_id', sanitize_text_field($_POST['product_id']));
TigerStyleSEO_Utils::update_option('product_mpn', sanitize_text_field($_POST['product_mpn']));
TigerStyleSEO_Utils::update_option('product_gtin', sanitize_text_field($_POST['product_gtin']));
TigerStyleSEO_Utils::update_option('product_gtin8', sanitize_text_field($_POST['product_gtin8']));
TigerStyleSEO_Utils::update_option('product_gtin12', sanitize_text_field($_POST['product_gtin12']));
TigerStyleSEO_Utils::update_option('product_gtin13', sanitize_text_field($_POST['product_gtin13']));
TigerStyleSEO_Utils::update_option('product_gtin14', sanitize_text_field($_POST['product_gtin14']));
// Physical properties
TigerStyleSEO_Utils::update_option('product_color', sanitize_text_field($_POST['product_color']));
TigerStyleSEO_Utils::update_option('product_size', sanitize_text_field($_POST['product_size']));
TigerStyleSEO_Utils::update_option('product_material', sanitize_text_field($_POST['product_material']));
TigerStyleSEO_Utils::update_option('product_pattern', sanitize_text_field($_POST['product_pattern']));
TigerStyleSEO_Utils::update_option('product_model', sanitize_text_field($_POST['product_model']));
TigerStyleSEO_Utils::update_option('product_condition', sanitize_text_field($_POST['product_condition']));
// Dimensions and weight
TigerStyleSEO_Utils::update_option('product_width', floatval($_POST['product_width']));
TigerStyleSEO_Utils::update_option('product_width_unit', sanitize_text_field($_POST['product_width_unit']));
TigerStyleSEO_Utils::update_option('product_height', floatval($_POST['product_height']));
TigerStyleSEO_Utils::update_option('product_height_unit', sanitize_text_field($_POST['product_height_unit']));
TigerStyleSEO_Utils::update_option('product_depth', floatval($_POST['product_depth']));
TigerStyleSEO_Utils::update_option('product_depth_unit', sanitize_text_field($_POST['product_depth_unit']));
TigerStyleSEO_Utils::update_option('product_weight', floatval($_POST['product_weight']));
TigerStyleSEO_Utils::update_option('product_weight_unit', sanitize_text_field($_POST['product_weight_unit']));
// Dates
TigerStyleSEO_Utils::update_option('product_production_date', sanitize_text_field($_POST['product_production_date']));
TigerStyleSEO_Utils::update_option('product_release_date', sanitize_text_field($_POST['product_release_date']));
// Pricing and availability
TigerStyleSEO_Utils::update_option('product_price', floatval($_POST['product_price']));
TigerStyleSEO_Utils::update_option('product_currency', sanitize_text_field($_POST['product_currency']));
TigerStyleSEO_Utils::update_option('product_availability', sanitize_text_field($_POST['product_availability']));
TigerStyleSEO_Utils::update_option('product_price_valid_until', sanitize_text_field($_POST['product_price_valid_until']));
TigerStyleSEO_Utils::update_option('product_seller', sanitize_text_field($_POST['product_seller']));
TigerStyleSEO_Utils::update_option('product_buy_url', esc_url_raw($_POST['product_buy_url']));
// Brand and manufacturer
TigerStyleSEO_Utils::update_option('product_brand_name', sanitize_text_field($_POST['product_brand_name']));
TigerStyleSEO_Utils::update_option('product_brand_logo', esc_url_raw($_POST['product_brand_logo']));
TigerStyleSEO_Utils::update_option('product_manufacturer', sanitize_text_field($_POST['product_manufacturer']));
// Reviews and ratings
TigerStyleSEO_Utils::update_option('product_rating_value', floatval($_POST['product_rating_value']));
TigerStyleSEO_Utils::update_option('product_rating_count', intval($_POST['product_rating_count']));
TigerStyleSEO_Utils::update_option('product_worst_rating', intval($_POST['product_worst_rating']));
TigerStyleSEO_Utils::update_option('product_best_rating', intval($_POST['product_best_rating']));
TigerStyleSEO_Utils::update_option('product_reviews', sanitize_textarea_field($_POST['product_reviews']));
// Additional information
TigerStyleSEO_Utils::update_option('product_images', sanitize_textarea_field($_POST['product_images']));
TigerStyleSEO_Utils::update_option('product_awards', sanitize_text_field($_POST['product_awards']));
TigerStyleSEO_Utils::update_option('product_audience', sanitize_text_field($_POST['product_audience']));
TigerStyleSEO_Utils::update_option('product_positive_notes', sanitize_text_field($_POST['product_positive_notes']));
TigerStyleSEO_Utils::update_option('product_negative_notes', sanitize_text_field($_POST['product_negative_notes']));
TigerStyleSEO_Utils::update_option('product_additional_properties', sanitize_textarea_field($_POST['product_additional_properties']));
// Save Article settings
TigerStyleSEO_Utils::update_option('article_enabled', isset($_POST['article_enabled']) && $_POST['article_enabled'] === '1');
TigerStyleSEO_Utils::update_option('article_auto_detect', isset($_POST['article_auto_detect']) && $_POST['article_auto_detect'] === '1');
TigerStyleSEO_Utils::update_option('article_manual_enable', isset($_POST['article_manual_enable']) && $_POST['article_manual_enable'] === '1');
TigerStyleSEO_Utils::update_option('article_auto_extract_images', isset($_POST['article_auto_extract_images']) && $_POST['article_auto_extract_images'] === '1');
TigerStyleSEO_Utils::update_option('article_auto_extract_keywords', isset($_POST['article_auto_extract_keywords']) && $_POST['article_auto_extract_keywords'] === '1');
TigerStyleSEO_Utils::update_option('article_type', sanitize_text_field($_POST['article_type']));
// Article content
TigerStyleSEO_Utils::update_option('article_headline', sanitize_text_field($_POST['article_headline']));
TigerStyleSEO_Utils::update_option('article_alternative_headline', sanitize_text_field($_POST['article_alternative_headline']));
TigerStyleSEO_Utils::update_option('article_description', sanitize_textarea_field($_POST['article_description']));
TigerStyleSEO_Utils::update_option('article_section', sanitize_text_field($_POST['article_section']));
TigerStyleSEO_Utils::update_option('article_keywords', sanitize_textarea_field($_POST['article_keywords']));
TigerStyleSEO_Utils::update_option('article_images', sanitize_textarea_field($_POST['article_images']));
// Author information
TigerStyleSEO_Utils::update_option('article_author_name', sanitize_text_field($_POST['article_author_name']));
TigerStyleSEO_Utils::update_option('article_author_url', esc_url_raw($_POST['article_author_url']));
TigerStyleSEO_Utils::update_option('article_author_description', sanitize_textarea_field($_POST['article_author_description']));
// Publisher information
TigerStyleSEO_Utils::update_option('article_publisher_name', sanitize_text_field($_POST['article_publisher_name']));
TigerStyleSEO_Utils::update_option('article_publisher_logo', esc_url_raw($_POST['article_publisher_logo']));
TigerStyleSEO_Utils::update_option('article_publisher_url', esc_url_raw($_POST['article_publisher_url']));
TigerStyleSEO_Utils::update_option('article_blog_name', sanitize_text_field($_POST['article_blog_name']));
// News article properties
TigerStyleSEO_Utils::update_option('article_dateline', sanitize_text_field($_POST['article_dateline']));
TigerStyleSEO_Utils::update_option('article_print_page', sanitize_text_field($_POST['article_print_page']));
TigerStyleSEO_Utils::update_option('article_print_section', sanitize_text_field($_POST['article_print_section']));
TigerStyleSEO_Utils::update_option('article_print_edition', sanitize_text_field($_POST['article_print_edition']));
TigerStyleSEO_Utils::update_option('article_print_column', sanitize_text_field($_POST['article_print_column']));
// Additional properties
TigerStyleSEO_Utils::update_option('article_language', sanitize_text_field($_POST['article_language']));
TigerStyleSEO_Utils::update_option('article_copyright_holder', sanitize_text_field($_POST['article_copyright_holder']));
TigerStyleSEO_Utils::update_option('article_copyright_year', intval($_POST['article_copyright_year']));
TigerStyleSEO_Utils::update_option('article_license', esc_url_raw($_POST['article_license']));
TigerStyleSEO_Utils::update_option('article_rating', sanitize_text_field($_POST['article_rating']));
// Save Google Site Verification settings
$verification_method = sanitize_text_field($_POST['google_verification_method'] ?? '');
$verification_code = sanitize_text_field($_POST['google_verification_code'] ?? '');
TigerStyleSEO_Utils::update_option('google_verification_method', $verification_method);
TigerStyleSEO_Utils::update_option('google_verification_code', $verification_code);
TigerStyleSEO_Utils::redirect_with_message('google_appearance_updated');
} catch (Exception $e) {
TigerStyleSEO_Utils::redirect_with_message('error');
}
}
/**
* Render admin page
*/
public function render_admin_page() {
include TIGERSTYLE_HEAT_PLUGIN_DIR . 'admin/pages/google-appearance.php';
}
/**
* Generate Organization structured data
*/
private function get_organization_schema() {
$org_name = TigerStyleSEO_Utils::get_option('organization_name', get_bloginfo('name'));
if (empty($org_name)) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'Organization',
'name' => $org_name,
'url' => home_url()
);
// Add optional fields if they exist
$logo = TigerStyleSEO_Utils::get_option('organization_logo', '');
if (!empty($logo)) {
$schema['logo'] = $logo;
}
$description = TigerStyleSEO_Utils::get_option('organization_description', '');
if (!empty($description)) {
$schema['description'] = $description;
}
$email = TigerStyleSEO_Utils::get_option('organization_email', '');
if (!empty($email)) {
$schema['email'] = $email;
}
$phone = TigerStyleSEO_Utils::get_option('organization_phone', '');
if (!empty($phone)) {
$schema['telephone'] = $phone;
}
// Social media profiles
$social_profiles = TigerStyleSEO_Utils::get_option('organization_social_profiles', '');
if (!empty($social_profiles)) {
$profiles = array_filter(array_map('trim', explode("\n", $social_profiles)));
if (!empty($profiles)) {
$schema['sameAs'] = $profiles;
}
}
return $schema;
}
/**
* Generate Local Business structured data
*/
private function get_local_business_schema() {
$business_name = TigerStyleSEO_Utils::get_option('organization_name', get_bloginfo('name'));
$street = TigerStyleSEO_Utils::get_option('business_address_street', '');
if (empty($business_name) || empty($street)) {
return null;
}
$business_type = TigerStyleSEO_Utils::get_option('business_type', 'LocalBusiness');
$schema = array(
'@context' => 'https://schema.org',
'@type' => $business_type,
'name' => $business_name,
'address' => array(
'@type' => 'PostalAddress',
'streetAddress' => $street,
'addressLocality' => TigerStyleSEO_Utils::get_option('business_address_city', ''),
'addressRegion' => TigerStyleSEO_Utils::get_option('business_address_state', ''),
'postalCode' => TigerStyleSEO_Utils::get_option('business_address_zip', ''),
'addressCountry' => TigerStyleSEO_Utils::get_option('business_address_country', 'US')
)
);
// Add coordinates if available
$latitude = TigerStyleSEO_Utils::get_option('business_latitude', '');
$longitude = TigerStyleSEO_Utils::get_option('business_longitude', '');
if (!empty($latitude) && !empty($longitude)) {
$schema['geo'] = array(
'@type' => 'GeoCoordinates',
'latitude' => floatval($latitude),
'longitude' => floatval($longitude)
);
}
// Add contact information
$phone = TigerStyleSEO_Utils::get_option('organization_phone', '');
if (!empty($phone)) {
$schema['telephone'] = $phone;
}
// Add business hours
$hours = TigerStyleSEO_Utils::get_option('business_hours', '');
if (!empty($hours)) {
$hours_lines = array_filter(array_map('trim', explode("\n", $hours)));
$opening_hours = array();
foreach ($hours_lines as $line) {
if (strpos($line, 'closed') === false && preg_match('/^(.+?)\s+(\d{2}:\d{2})-(\d{2}:\d{2})$/', $line, $matches)) {
$days = $matches[1];
$open_time = $matches[2];
$close_time = $matches[3];
$opening_hours[] = array(
'@type' => 'OpeningHoursSpecification',
'dayOfWeek' => TigerStyleSEO_Utils::parse_business_days($days),
'opens' => $open_time,
'closes' => $close_time
);
}
}
if (!empty($opening_hours)) {
$schema['openingHoursSpecification'] = $opening_hours;
}
}
// Add price range
$price_range = TigerStyleSEO_Utils::get_option('business_price_range', '');
if (!empty($price_range)) {
$schema['priceRange'] = $price_range;
}
return $schema;
}
/**
* Generate Return Policy structured data
*/
private function get_return_policy_schema() {
if (!TigerStyleSEO_Utils::get_option('return_policy_enabled', false)) {
return null;
}
$policy_type = TigerStyleSEO_Utils::get_option('return_policy_type', 'MerchantReturnPolicy');
if ($policy_type === 'ProductReturnPolicy') {
return $this->get_product_return_policy();
} else {
return $this->get_merchant_return_policy();
}
}
/**
* Generate basic ProductReturnPolicy structured data
*/
private function get_product_return_policy() {
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'ProductReturnPolicy'
);
// Return policy category
$category = TigerStyleSEO_Utils::get_option('return_policy_category', '');
if (!empty($category)) {
$schema['returnPolicyCategory'] = $category;
}
// Number of days for return
$days = TigerStyleSEO_Utils::get_option('return_policy_days', '');
if (!empty($days) && is_numeric($days)) {
$schema['returnPolicyDays'] = intval($days);
}
// Return policy URL
$url = TigerStyleSEO_Utils::get_option('return_policy_url', '');
if (!empty($url)) {
$schema['returnPolicyURL'] = $url;
}
// Country where policy applies
$country = TigerStyleSEO_Utils::get_option('return_policy_country', '');
if (!empty($country)) {
$schema['returnPolicyCountry'] = $country;
}
return $schema;
}
/**
* Generate comprehensive MerchantReturnPolicy structured data
*/
private function get_merchant_return_policy() {
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'MerchantReturnPolicy'
);
// Basic properties
$applicable_country = TigerStyleSEO_Utils::get_option('merchant_return_country', '');
if (!empty($applicable_country)) {
$schema['applicableCountry'] = $applicable_country;
}
$return_policy_category = TigerStyleSEO_Utils::get_option('merchant_return_category', '');
if (!empty($return_policy_category)) {
$schema['returnPolicyCategory'] = $return_policy_category;
}
$return_days = TigerStyleSEO_Utils::get_option('merchant_return_days', '');
if (!empty($return_days) && is_numeric($return_days)) {
$schema['merchantReturnDays'] = intval($return_days);
}
// Return method
$return_method = TigerStyleSEO_Utils::get_option('merchant_return_method', '');
if (!empty($return_method)) {
$schema['returnMethod'] = $return_method;
}
// Return fees for customer remorse
$customer_remorse_fees = TigerStyleSEO_Utils::get_option('customer_remorse_return_fees', '');
if (!empty($customer_remorse_fees)) {
$schema['customerRemorseReturnFees'] = array(
'@type' => 'MonetaryAmount',
'value' => floatval($customer_remorse_fees),
'currency' => TigerStyleSEO_Utils::get_option('return_policy_currency', 'USD')
);
}
// Return fees for defective items
$defect_fees = TigerStyleSEO_Utils::get_option('item_defect_return_fees', '');
if (!empty($defect_fees)) {
$schema['itemDefectReturnFees'] = array(
'@type' => 'MonetaryAmount',
'value' => floatval($defect_fees),
'currency' => TigerStyleSEO_Utils::get_option('return_policy_currency', 'USD')
);
}
// Shipping fees for customer remorse returns
$customer_shipping_fees = TigerStyleSEO_Utils::get_option('customer_remorse_shipping_fees', '');
if (!empty($customer_shipping_fees)) {
$schema['customerRemorseReturnShippingFeesAmount'] = array(
'@type' => 'MonetaryAmount',
'value' => floatval($customer_shipping_fees),
'currency' => TigerStyleSEO_Utils::get_option('return_policy_currency', 'USD')
);
}
// Shipping fees for defective items
$defect_shipping_fees = TigerStyleSEO_Utils::get_option('item_defect_shipping_fees', '');
if (!empty($defect_shipping_fees)) {
$schema['itemDefectReturnShippingFeesAmount'] = array(
'@type' => 'MonetaryAmount',
'value' => floatval($defect_shipping_fees),
'currency' => TigerStyleSEO_Utils::get_option('return_policy_currency', 'USD')
);
}
// Restocking fee
$restocking_fee = TigerStyleSEO_Utils::get_option('restocking_fee', '');
if (!empty($restocking_fee)) {
$schema['restockingFee'] = array(
'@type' => 'MonetaryAmount',
'value' => floatval($restocking_fee),
'currency' => TigerStyleSEO_Utils::get_option('return_policy_currency', 'USD')
);
}
// Return label source
$label_source = TigerStyleSEO_Utils::get_option('return_label_source', '');
if (!empty($label_source)) {
$schema['returnLabelSource'] = $label_source;
}
// Item condition for returns
$item_condition = TigerStyleSEO_Utils::get_option('return_item_condition', '');
if (!empty($item_condition)) {
$schema['itemCondition'] = $item_condition;
}
return $schema;
}
/**
* Generate Profile Page (Person) structured data
*/
private function get_profile_page_schema() {
// Check if profile page is enabled
if (!TigerStyleSEO_Utils::get_option('profile_page_enabled', false)) {
return null;
}
// Determine if this is an author page or a specific profile page
$is_author_page = is_author();
$use_page_specific = TigerStyleSEO_Utils::get_option('profile_use_page_specific', false);
if ($is_author_page) {
return $this->get_author_profile_schema();
} elseif ($use_page_specific && (is_page() || is_single())) {
return $this->get_page_specific_profile_schema();
}
return null;
}
/**
* Generate author profile structured data for author pages
*/
private function get_author_profile_schema() {
if (!is_author()) {
return null;
}
$author_id = get_query_var('author');
$author = get_userdata($author_id);
if (!$author) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'Person',
'name' => $author->display_name
);
// Add author URL
$author_url = get_author_posts_url($author_id);
if ($author_url) {
$schema['url'] = $author_url;
}
// Add description from bio
$description = get_user_meta($author_id, 'description', true);
if (!empty($description)) {
$schema['description'] = wp_strip_all_tags($description);
}
// Add email (if public)
if (TigerStyleSEO_Utils::get_option('profile_show_author_email', false)) {
$schema['email'] = 'mailto:' . $author->user_email;
}
// Add avatar image
$avatar_url = get_avatar_url($author_id, array('size' => 300));
if ($avatar_url) {
$schema['image'] = $avatar_url;
}
// Add job title from user meta
$job_title = get_user_meta($author_id, 'job_title', true);
if (!empty($job_title)) {
$schema['jobTitle'] = $job_title;
}
// Add social profiles
$social_profiles = array();
$social_fields = array('twitter', 'facebook', 'linkedin', 'instagram', 'youtube', 'website');
foreach ($social_fields as $field) {
$url = get_user_meta($author_id, $field, true);
if (!empty($url)) {
$social_profiles[] = $url;
}
}
if (!empty($social_profiles)) {
$schema['sameAs'] = $social_profiles;
}
return $schema;
}
/**
* Generate page-specific profile structured data
*/
private function get_page_specific_profile_schema() {
$person_name = TigerStyleSEO_Utils::get_option('profile_person_name', '');
if (empty($person_name)) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'Person',
'name' => $person_name
);
// Add basic information
$job_title = TigerStyleSEO_Utils::get_option('profile_job_title', '');
if (!empty($job_title)) {
$schema['jobTitle'] = $job_title;
}
$description = TigerStyleSEO_Utils::get_option('profile_description', '');
if (!empty($description)) {
$schema['description'] = $description;
}
$email = TigerStyleSEO_Utils::get_option('profile_email', '');
if (!empty($email)) {
$schema['email'] = 'mailto:' . $email;
}
$phone = TigerStyleSEO_Utils::get_option('profile_phone', '');
if (!empty($phone)) {
$schema['telephone'] = $phone;
}
$website = TigerStyleSEO_Utils::get_option('profile_website', '');
if (!empty($website)) {
$schema['url'] = $website;
}
$image = TigerStyleSEO_Utils::get_option('profile_image', '');
if (!empty($image)) {
$schema['image'] = $image;
}
// Add address if provided
$street = TigerStyleSEO_Utils::get_option('profile_address_street', '');
$city = TigerStyleSEO_Utils::get_option('profile_address_city', '');
$region = TigerStyleSEO_Utils::get_option('profile_address_region', '');
$postal_code = TigerStyleSEO_Utils::get_option('profile_address_postal_code', '');
$country = TigerStyleSEO_Utils::get_option('profile_address_country', '');
if (!empty($street) || !empty($city)) {
$address = array('@type' => 'PostalAddress');
if (!empty($street)) $address['streetAddress'] = $street;
if (!empty($city)) $address['addressLocality'] = $city;
if (!empty($region)) $address['addressRegion'] = $region;
if (!empty($postal_code)) $address['postalCode'] = $postal_code;
if (!empty($country)) $address['addressCountry'] = $country;
$schema['address'] = $address;
}
// Add social media profiles
$social_profiles = array();
$social_urls = TigerStyleSEO_Utils::get_option('profile_social_profiles', '');
if (!empty($social_urls)) {
$profiles = array_filter(array_map('trim', explode("\n", $social_urls)));
if (!empty($profiles)) {
$schema['sameAs'] = $profiles;
}
}
// Add organization affiliation
$organization = TigerStyleSEO_Utils::get_option('profile_organization', '');
if (!empty($organization)) {
$schema['affiliation'] = array(
'@type' => 'Organization',
'name' => $organization
);
}
// Add colleagues/knows relationships
$colleagues = TigerStyleSEO_Utils::get_option('profile_colleagues', '');
if (!empty($colleagues)) {
$colleague_urls = array_filter(array_map('trim', explode("\n", $colleagues)));
if (!empty($colleague_urls)) {
$schema['colleague'] = $colleague_urls;
}
}
return $schema;
}
/**
* Generate QAPage structured data
*/
private function get_qapage_schema() {
// Check if QAPage is enabled
if (!TigerStyleSEO_Utils::get_option('qapage_enabled', false)) {
return null;
}
// Check if this should be treated as a QAPage
$is_qapage = $this->is_qapage_content();
if (!$is_qapage) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'QAPage'
);
// Add basic page information
if (is_single() || is_page()) {
global $post;
$schema['name'] = get_the_title();
$schema['url'] = get_permalink();
if (!empty($post->post_excerpt)) {
$schema['description'] = wp_strip_all_tags($post->post_excerpt);
} else {
$schema['description'] = wp_strip_all_tags(wp_trim_words($post->post_content, 25));
}
$schema['datePublished'] = get_the_date('c');
$schema['dateModified'] = get_the_modified_date('c');
// Add author information
$author_id = $post->post_author;
$author = get_userdata($author_id);
if ($author) {
$schema['author'] = array(
'@type' => 'Person',
'name' => $author->display_name,
'url' => get_author_posts_url($author_id)
);
}
}
// Add main question/answer content
$main_entity = $this->get_main_question_schema();
if (!empty($main_entity)) {
$schema['mainEntity'] = $main_entity;
}
return $schema;
}
/**
* Determine if current content should be treated as QAPage
*/
private function is_qapage_content() {
// Check if manually enabled for this page
$manual_enable = TigerStyleSEO_Utils::get_option('qapage_manual_enable', false);
if ($manual_enable && (is_page() || is_single())) {
return true;
}
// Auto-detect based on content patterns
$auto_detect = TigerStyleSEO_Utils::get_option('qapage_auto_detect', false);
if (!$auto_detect) {
return false;
}
if (is_single() || is_page()) {
global $post;
$content = $post->post_content;
$title = $post->post_title;
// Check for FAQ patterns
$faq_patterns = array(
'/frequently\s+asked\s+questions/i',
'/f\.a\.q/i',
'/\bfaq\b/i',
'/questions?\s+and\s+answers?/i',
'/q\s*&\s*a/i'
);
foreach ($faq_patterns as $pattern) {
if (preg_match($pattern, $title) || preg_match($pattern, $content)) {
return true;
}
}
// Check for question patterns in title
$question_patterns = array(
'/^(what|how|why|when|where|who|which|can|is|are|do|does|will|would|should)\s+/i',
'/\?$/'
);
foreach ($question_patterns as $pattern) {
if (preg_match($pattern, $title)) {
return true;
}
}
}
return false;
}
/**
* Generate main Question schema for QAPage
*/
private function get_main_question_schema() {
global $post;
if (!$post) {
return null;
}
$question_text = TigerStyleSEO_Utils::get_option('qapage_question_text', '');
$answer_text = TigerStyleSEO_Utils::get_option('qapage_answer_text', '');
// If manual Q&A is provided, use it
if (!empty($question_text) && !empty($answer_text)) {
return $this->build_question_schema($question_text, $answer_text);
}
// Auto-extract from content
$auto_extract = TigerStyleSEO_Utils::get_option('qapage_auto_extract', true);
if ($auto_extract) {
return $this->extract_question_from_content($post);
}
return null;
}
/**
* Build Question schema with answer
*/
private function build_question_schema($question_text, $answer_text, $author_name = null) {
$schema = array(
'@type' => 'Question',
'name' => $question_text,
'text' => $question_text
);
// Add answer
$answer_schema = array(
'@type' => 'Answer',
'text' => $answer_text
);
// Add author if provided
if (!empty($author_name)) {
$answer_schema['author'] = array(
'@type' => 'Person',
'name' => $author_name
);
} else {
// Use post author
global $post;
if ($post) {
$author = get_userdata($post->post_author);
if ($author) {
$answer_schema['author'] = array(
'@type' => 'Person',
'name' => $author->display_name
);
}
}
}
// Add dates
if (is_single() || is_page()) {
$answer_schema['dateCreated'] = get_the_date('c');
$schema['dateCreated'] = get_the_date('c');
}
$schema['acceptedAnswer'] = $answer_schema;
$schema['answerCount'] = 1;
return $schema;
}
/**
* Extract question and answer from post content
*/
private function extract_question_from_content($post) {
$title = $post->post_title;
$content = $post->post_content;
// Use title as question if it looks like a question
$question_text = $title;
// Clean content for answer
$answer_text = wp_strip_all_tags($content);
$answer_text = wp_trim_words($answer_text, 100);
// If title doesn't look like a question, try to find one in content
if (!preg_match('/\?$/', $title) && !preg_match('/^(what|how|why|when|where|who|which|can|is|are|do|does|will|would|should)\s+/i', $title)) {
// Look for question patterns in content
$questions = array();
preg_match_all('/([^.!?]*\?)/i', $content, $questions);
if (!empty($questions[1])) {
$question_text = wp_strip_all_tags(trim($questions[1][0]));
// Get content after the question as answer
$parts = explode($questions[1][0], $content, 2);
if (count($parts) > 1) {
$answer_text = wp_strip_all_tags($parts[1]);
$answer_text = wp_trim_words($answer_text, 100);
}
}
}
if (empty($question_text) || empty($answer_text)) {
return null;
}
return $this->build_question_schema($question_text, $answer_text);
}
/**
* Generate Speakable structured data
*/
private function get_speakable_schema() {
// Check if Speakable is enabled
if (!TigerStyleSEO_Utils::get_option('speakable_enabled', false)) {
return null;
}
// Only apply to pages and posts
if (!is_single() && !is_page()) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'WebPage'
);
// Add basic page information
global $post;
if ($post) {
$schema['name'] = get_the_title();
$schema['url'] = get_permalink();
}
// Add speakable specifications
$speakable_spec = $this->get_speakable_specification();
if (!empty($speakable_spec)) {
$schema['speakable'] = $speakable_spec;
}
return $schema;
}
/**
* Generate SpeakableSpecification with CSS selectors and XPath
*/
private function get_speakable_specification() {
$css_selectors = $this->get_speakable_css_selectors();
$xpath_expressions = $this->get_speakable_xpath_expressions();
// If no selectors defined, return null
if (empty($css_selectors) && empty($xpath_expressions)) {
return null;
}
$spec = array(
'@type' => 'SpeakableSpecification'
);
// Add CSS selectors
if (!empty($css_selectors)) {
$spec['cssSelector'] = $css_selectors;
}
// Add XPath expressions
if (!empty($xpath_expressions)) {
$spec['xpath'] = $xpath_expressions;
}
return $spec;
}
/**
* Get CSS selectors for speakable content
*/
private function get_speakable_css_selectors() {
$selectors = array();
// Get manual CSS selectors from settings
$manual_selectors = TigerStyleSEO_Utils::get_option('speakable_css_selectors', '');
if (!empty($manual_selectors)) {
$manual_array = array_map('trim', explode(',', $manual_selectors));
$selectors = array_merge($selectors, array_filter($manual_array));
}
// Auto-detect common selectors if enabled
$auto_detect = TigerStyleSEO_Utils::get_option('speakable_auto_detect', true);
if ($auto_detect) {
$auto_selectors = $this->get_auto_detected_speakable_selectors();
$selectors = array_merge($selectors, $auto_selectors);
}
return array_unique($selectors);
}
/**
* Get XPath expressions for speakable content
*/
private function get_speakable_xpath_expressions() {
$expressions = array();
// Get manual XPath expressions from settings
$manual_xpath = TigerStyleSEO_Utils::get_option('speakable_xpath_expressions', '');
if (!empty($manual_xpath)) {
$manual_array = array_map('trim', explode(',', $manual_xpath));
$expressions = array_merge($expressions, array_filter($manual_array));
}
return array_unique($expressions);
}
/**
* Auto-detect common CSS selectors for speakable content
*/
private function get_auto_detected_speakable_selectors() {
$selectors = array();
// Common title/heading selectors
$include_headings = TigerStyleSEO_Utils::get_option('speakable_include_headings', true);
if ($include_headings) {
$selectors[] = 'h1';
$selectors[] = 'h2';
$selectors[] = '.entry-title';
$selectors[] = '.post-title';
$selectors[] = '.page-title';
}
// Common content selectors
$include_content = TigerStyleSEO_Utils::get_option('speakable_include_content', false);
if ($include_content) {
$selectors[] = '.entry-content';
$selectors[] = '.post-content';
$selectors[] = '.content';
$selectors[] = 'main';
}
// Summary/excerpt selectors
$include_summary = TigerStyleSEO_Utils::get_option('speakable_include_summary', true);
if ($include_summary) {
$selectors[] = '.entry-summary';
$selectors[] = '.post-excerpt';
$selectors[] = '.summary';
$selectors[] = '.excerpt';
}
// Navigation elements for accessibility
$include_nav = TigerStyleSEO_Utils::get_option('speakable_include_navigation', false);
if ($include_nav) {
$selectors[] = 'nav';
$selectors[] = '.navigation';
$selectors[] = '.menu';
}
return $selectors;
}
/**
* Generate Video structured data
*/
private function get_video_schema() {
// Check if Video is enabled
if (!TigerStyleSEO_Utils::get_option('video_enabled', false)) {
return null;
}
// Only apply to pages and posts
if (!is_single() && !is_page()) {
return null;
}
// Check if content contains video
$video_data = $this->detect_video_content();
if (empty($video_data)) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'VideoObject'
);
// Add basic video information
global $post;
if ($post) {
// Use post title or custom video title
$video_title = TigerStyleSEO_Utils::get_option('video_custom_title', '');
$schema['name'] = !empty($video_title) ? $video_title : get_the_title();
// Video description
$video_description = TigerStyleSEO_Utils::get_option('video_description', '');
if (!empty($video_description)) {
$schema['description'] = $video_description;
} elseif (!empty($post->post_excerpt)) {
$schema['description'] = wp_strip_all_tags($post->post_excerpt);
} else {
$schema['description'] = wp_strip_all_tags(wp_trim_words($post->post_content, 25));
}
// Add dates
$schema['datePublished'] = get_the_date('c');
$schema['dateModified'] = get_the_modified_date('c');
// Add author information
$author_id = $post->post_author;
$author = get_userdata($author_id);
if ($author) {
$schema['author'] = array(
'@type' => 'Person',
'name' => $author->display_name,
'url' => get_author_posts_url($author_id)
);
}
}
// Merge detected video data
$schema = array_merge($schema, $video_data);
// Add optional video properties
$this->add_video_optional_properties($schema);
return $schema;
}
/**
* Detect video content in post
*/
private function detect_video_content() {
global $post;
if (!$post) {
return array();
}
$video_data = array();
$content = $post->post_content;
// Manual video URL override
$manual_url = TigerStyleSEO_Utils::get_option('video_url', '');
if (!empty($manual_url)) {
$video_data['contentUrl'] = esc_url($manual_url);
$video_data['embedUrl'] = esc_url($manual_url);
} else {
// Auto-detect video embeds
$video_urls = $this->extract_video_urls($content);
if (!empty($video_urls)) {
$video_data['contentUrl'] = $video_urls[0];
$video_data['embedUrl'] = $video_urls[0];
}
}
// Add thumbnail if provided
$thumbnail_url = TigerStyleSEO_Utils::get_option('video_thumbnail', '');
if (!empty($thumbnail_url)) {
$video_data['thumbnailUrl'] = esc_url($thumbnail_url);
} else {
// Try to get featured image as thumbnail
$thumbnail_id = get_post_thumbnail_id();
if ($thumbnail_id) {
$thumbnail_info = wp_get_attachment_image_src($thumbnail_id, 'large');
if ($thumbnail_info) {
$video_data['thumbnailUrl'] = $thumbnail_info[0];
}
}
}
// Add duration if provided
$duration = TigerStyleSEO_Utils::get_option('video_duration', '');
if (!empty($duration)) {
// Convert to ISO 8601 duration format if needed
$video_data['duration'] = $this->format_video_duration($duration);
}
// Add upload date
$upload_date = TigerStyleSEO_Utils::get_option('video_upload_date', '');
if (!empty($upload_date)) {
$video_data['uploadDate'] = date('c', strtotime($upload_date));
} else {
$video_data['uploadDate'] = get_the_date('c');
}
return $video_data;
}
/**
* Extract video URLs from content
*/
private function extract_video_urls($content) {
$video_urls = array();
// YouTube URLs
if (preg_match_all('/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/i', $content, $youtube_matches)) {
foreach ($youtube_matches[1] as $video_id) {
$video_urls[] = 'https://www.youtube.com/watch?v=' . $video_id;
}
}
// Vimeo URLs
if (preg_match_all('/vimeo\.com\/(?:.*#|\/)?([0-9]+)/i', $content, $vimeo_matches)) {
foreach ($vimeo_matches[1] as $video_id) {
$video_urls[] = 'https://vimeo.com/' . $video_id;
}
}
// Generic video file URLs
if (preg_match_all('/https?:\/\/[^\s]+\.(mp4|webm|ogg|avi|mov)/i', $content, $file_matches)) {
$video_urls = array_merge($video_urls, $file_matches[0]);
}
// HTML5 video tags
if (preg_match_all('/<video[^>]*>.*?<source[^>]+src=["\']([^"\'\/]+)["\'][^>]*>.*?<\/video>/is', $content, $html5_matches)) {
$video_urls = array_merge($video_urls, $html5_matches[1]);
}
return array_unique($video_urls);
}
/**
* Format video duration to ISO 8601 format
*/
private function format_video_duration($duration) {
// If already in ISO 8601 format, return as is
if (preg_match('/^P(?:\d+D)?(?:T(?:\d+H)?(?:\d+M)?(?:\d+(?:\.\d+)?S)?)?$/', $duration)) {
return $duration;
}
// Parse common formats: "5:30", "1:05:30", "90" (seconds)
if (preg_match('/^(\d+):(\d+):(\d+)$/', $duration, $matches)) {
// H:M:S format
return sprintf('PT%dH%dM%dS', intval($matches[1]), intval($matches[2]), intval($matches[3]));
} elseif (preg_match('/^(\d+):(\d+)$/', $duration, $matches)) {
// M:S format
return sprintf('PT%dM%dS', intval($matches[1]), intval($matches[2]));
} elseif (is_numeric($duration)) {
// Seconds only
return sprintf('PT%dS', intval($duration));
}
return $duration;
}
/**
* Add optional video properties
*/
private function add_video_optional_properties(&$schema) {
// Video quality
$quality = TigerStyleSEO_Utils::get_option('video_quality', '');
if (!empty($quality)) {
$schema['videoQuality'] = $quality;
}
// Video frame size
$width = TigerStyleSEO_Utils::get_option('video_width', '');
$height = TigerStyleSEO_Utils::get_option('video_height', '');
if (!empty($width) && !empty($height)) {
$schema['videoFrameSize'] = $width . 'x' . $height;
}
// Transcript
$transcript = TigerStyleSEO_Utils::get_option('video_transcript', '');
if (!empty($transcript)) {
$schema['transcript'] = $transcript;
}
// Captions
$captions = TigerStyleSEO_Utils::get_option('video_captions', '');
if (!empty($captions)) {
$schema['caption'] = $captions;
}
// Genre
$genre = TigerStyleSEO_Utils::get_option('video_genre', '');
if (!empty($genre)) {
$schema['genre'] = $genre;
}
// Director
$director = TigerStyleSEO_Utils::get_option('video_director', '');
if (!empty($director)) {
$schema['director'] = array(
'@type' => 'Person',
'name' => $director
);
}
// Actors
$actors = TigerStyleSEO_Utils::get_option('video_actors', '');
if (!empty($actors)) {
$actor_list = array_map('trim', explode(',', $actors));
$schema['actor'] = array();
foreach ($actor_list as $actor_name) {
if (!empty($actor_name)) {
$schema['actor'][] = array(
'@type' => 'Person',
'name' => $actor_name
);
}
}
}
// Music by
$music_by = TigerStyleSEO_Utils::get_option('video_music_by', '');
if (!empty($music_by)) {
$schema['musicBy'] = array(
'@type' => 'Person',
'name' => $music_by
);
}
// Content rating
$content_rating = TigerStyleSEO_Utils::get_option('video_content_rating', '');
if (!empty($content_rating)) {
$schema['contentRating'] = $content_rating;
}
// Production company
$production_company = TigerStyleSEO_Utils::get_option('video_production_company', '');
if (!empty($production_company)) {
$schema['productionCompany'] = array(
'@type' => 'Organization',
'name' => $production_company
);
}
}
/**
* Generate Image structured data for all images
*/
private function get_image_schema() {
// Check if Image metadata is enabled
if (!TigerStyleSEO_Utils::get_option('imageobject_enabled', false)) {
return array();
}
// Only apply to pages and posts
if (!is_single() && !is_page()) {
return array();
}
global $post;
if (!$post) {
return array();
}
$image_schemas = array();
$processed_images = array();
// Get max images per page setting
$max_images = TigerStyleSEO_Utils::get_option('imageobject_max_per_page', 10);
$prioritize_featured = TigerStyleSEO_Utils::get_option('imageobject_prioritize_featured', true);
// Collect all images from different sources
$all_images = array();
// 1. Featured image (highest priority)
if (TigerStyleSEO_Utils::get_option('imageobject_include_featured', true)) {
$featured_image = $this->get_featured_image_data($post->ID);
if ($featured_image) {
$featured_image['priority'] = 1;
$featured_image['context'] = 'featured';
$all_images[] = $featured_image;
}
}
// 2. Content images (medium priority)
if (TigerStyleSEO_Utils::get_option('imageobject_include_content', true)) {
$content_images = $this->get_content_images_data($post->ID);
foreach ($content_images as $image) {
$image['priority'] = 2;
$image['context'] = 'content';
$all_images[] = $image;
}
}
// 3. Gallery images (lower priority)
if (TigerStyleSEO_Utils::get_option('imageobject_include_galleries', false)) {
$gallery_images = $this->get_gallery_images_data($post->ID);
foreach ($gallery_images as $image) {
$image['priority'] = 3;
$image['context'] = 'gallery';
$all_images[] = $image;
}
}
// Sort by priority if enabled
if ($prioritize_featured) {
usort($all_images, function($a, $b) {
return $a['priority'] - $b['priority'];
});
}
// Process images up to the limit
$count = 0;
foreach ($all_images as $image_data) {
if ($count >= $max_images) {
break;
}
// Skip duplicates
if (in_array($image_data['attachment_id'], $processed_images)) {
continue;
}
$schema = $this->build_image_schema($image_data);
if ($schema) {
$image_schemas[] = $schema;
$processed_images[] = $image_data['attachment_id'];
$count++;
}
}
return $image_schemas;
}
/**
* Get featured image data
*/
private function get_featured_image_data($post_id) {
$featured_id = get_post_thumbnail_id($post_id);
if (!$featured_id) {
return null;
}
return array(
'attachment_id' => $featured_id,
'representativeOfPage' => true,
'context' => 'featured'
);
}
/**
* Get content images data
*/
private function get_content_images_data($post_id) {
$post = get_post($post_id);
if (!$post) {
return array();
}
$images = array();
$content = $post->post_content;
// Find img tags in content
preg_match_all('/<img[^>]+>/i', $content, $img_matches);
foreach ($img_matches[0] as $img_tag) {
$image_data = $this->parse_img_tag($img_tag);
if ($image_data) {
$images[] = $image_data;
}
}
return $images;
}
/**
* Get gallery images data
*/
private function get_gallery_images_data($post_id) {
$post = get_post($post_id);
if (!$post) {
return array();
}
$images = array();
$content = $post->post_content;
// Find gallery shortcodes
preg_match_all('/\[gallery[^\]]*\]/i', $content, $gallery_matches);
foreach ($gallery_matches[0] as $shortcode) {
$gallery_images = $this->parse_gallery_shortcode($shortcode);
$images = array_merge($images, $gallery_images);
}
return $images;
}
/**
* Parse img tag to extract image data
*/
private function parse_img_tag($img_tag) {
// Extract src attribute
if (!preg_match('/src=["\']([^"\'\/]+)["\']/', $img_tag, $src_match)) {
return null;
}
$src = $src_match[1];
// Try to find WordPress attachment ID
$attachment_id = attachment_url_to_postid($src);
if (!$attachment_id) {
return null; // Skip external images for now
}
// Extract alt text
$alt_text = '';
if (preg_match('/alt=["\']([^"\'\/]*)["\']/', $img_tag, $alt_match)) {
$alt_text = $alt_match[1];
}
return array(
'attachment_id' => $attachment_id,
'alt_text' => $alt_text,
'context' => 'content'
);
}
/**
* Parse gallery shortcode to extract image IDs
*/
private function parse_gallery_shortcode($shortcode) {
$images = array();
// Extract IDs from gallery shortcode
if (preg_match('/ids=["\']([^"\'\/]+)["\']/', $shortcode, $ids_match)) {
$ids = explode(',', $ids_match[1]);
foreach ($ids as $id) {
$id = intval(trim($id));
if ($id > 0) {
$images[] = array(
'attachment_id' => $id,
'context' => 'gallery'
);
}
}
}
return $images;
}
/**
* Build ImageObject schema for a single image
*/
private function build_image_schema($image_data) {
$attachment_id = $image_data['attachment_id'];
// Check if image meets minimum criteria
if (!$this->should_process_image($attachment_id)) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'ImageObject'
);
// Get WordPress attachment data
$attachment = get_post($attachment_id);
if (!$attachment) {
return null;
}
// Basic properties
$schema['contentUrl'] = wp_get_attachment_url($attachment_id);
// Name (title)
$custom_name = get_post_meta($attachment_id, '_tigerstyle_image_name', true);
if (!empty($custom_name)) {
$schema['name'] = $custom_name;
} elseif (!empty($attachment->post_title)) {
$schema['name'] = $attachment->post_title;
}
// Description
$custom_description = get_post_meta($attachment_id, '_tigerstyle_image_description', true);
if (!empty($custom_description)) {
$schema['description'] = $custom_description;
} elseif (!empty($attachment->post_content)) {
$schema['description'] = wp_strip_all_tags($attachment->post_content);
} elseif (!empty($attachment->post_excerpt)) {
$schema['description'] = wp_strip_all_tags($attachment->post_excerpt);
}
// Alt text
$alt_text = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);
if (!empty($alt_text)) {
$schema['alternateName'] = $alt_text;
} elseif (!empty($image_data['alt_text'])) {
$schema['alternateName'] = $image_data['alt_text'];
}
// Technical properties
$wp_metadata = wp_get_attachment_metadata($attachment_id);
if (!empty($wp_metadata['width'])) {
$schema['width'] = intval($wp_metadata['width']);
}
if (!empty($wp_metadata['height'])) {
$schema['height'] = intval($wp_metadata['height']);
}
// File properties
$file_path = get_attached_file($attachment_id);
if ($file_path && file_exists($file_path)) {
$schema['contentSize'] = TigerStyleSEO_Utils::format_bytes(filesize($file_path));
$file_type = wp_check_filetype($file_path);
if (!empty($file_type['type'])) {
$schema['encodingFormat'] = $file_type['type'];
}
}
// Dates
$schema['uploadDate'] = get_the_date('c', $attachment_id);
$schema['datePublished'] = get_the_date('c', $attachment_id);
// Representative of page (for featured images)
if (!empty($image_data['representativeOfPage'])) {
$schema['representativeOfPage'] = true;
}
// Add author information
$this->add_image_author_info($schema, $attachment_id);
// Add copyright information
$this->add_image_copyright_info($schema, $attachment_id);
// Add EXIF data if enabled
if (TigerStyleSEO_Utils::get_option('imageobject_include_exif', false)) {
$this->add_image_exif_info($schema, $attachment_id);
}
return $schema;
}
/**
* Check if image should be processed for structured data
*/
private function should_process_image($attachment_id) {
// Check if it's actually an image
if (!wp_attachment_is_image($attachment_id)) {
return false;
}
// Check minimum dimensions
$min_width = TigerStyleSEO_Utils::get_option('imageobject_min_width', 300);
$min_height = TigerStyleSEO_Utils::get_option('imageobject_min_height', 200);
$metadata = wp_get_attachment_metadata($attachment_id);
if (empty($metadata['width']) || empty($metadata['height'])) {
return false;
}
if ($metadata['width'] < $min_width || $metadata['height'] < $min_height) {
return false;
}
return true;
}
/**
* Add author information to image schema
*/
private function add_image_author_info(&$schema, $attachment_id) {
// Check for custom author
$custom_author = get_post_meta($attachment_id, '_tigerstyle_image_author', true);
if (!empty($custom_author)) {
$schema['author'] = array(
'@type' => 'Person',
'name' => $custom_author
);
return;
}
// Use default author setting
$default_author = TigerStyleSEO_Utils::get_option('imageobject_default_author', '');
if (!empty($default_author)) {
$schema['author'] = array(
'@type' => 'Person',
'name' => $default_author
);
return;
}
// Use uploading user
$attachment = get_post($attachment_id);
if ($attachment) {
$author = get_userdata($attachment->post_author);
if ($author) {
$schema['author'] = array(
'@type' => 'Person',
'name' => $author->display_name
);
}
}
}
/**
* Add copyright information to image schema
*/
private function add_image_copyright_info(&$schema, $attachment_id) {
// Custom copyright holder
$custom_copyright = get_post_meta($attachment_id, '_tigerstyle_image_copyright_holder', true);
if (!empty($custom_copyright)) {
$schema['copyrightHolder'] = array(
'@type' => 'Person',
'name' => $custom_copyright
);
} else {
// Use default
$default_copyright = TigerStyleSEO_Utils::get_option('imageobject_default_copyright_holder', get_bloginfo('name'));
if (!empty($default_copyright)) {
$schema['copyrightHolder'] = array(
'@type' => 'Organization',
'name' => $default_copyright
);
}
}
// License information
$custom_license = get_post_meta($attachment_id, '_tigerstyle_image_license', true);
if (!empty($custom_license)) {
$schema['license'] = $custom_license;
} else {
// Use default license
$default_license = TigerStyleSEO_Utils::get_option('imageobject_default_license', '');
if (!empty($default_license)) {
$schema['license'] = $default_license;
}
}
// Copyright year
$copyright_year = get_post_meta($attachment_id, '_tigerstyle_image_copyright_year', true);
if (!empty($copyright_year)) {
$schema['copyrightYear'] = intval($copyright_year);
} else {
// Use upload year
$schema['copyrightYear'] = intval(get_the_date('Y', $attachment_id));
}
}
/**
* Add EXIF information to image schema
*/
private function add_image_exif_info(&$schema, $attachment_id) {
$file_path = get_attached_file($attachment_id);
if (!$file_path || !file_exists($file_path)) {
return;
}
// Check if EXIF functions are available
if (!function_exists('exif_read_data')) {
return;
}
try {
$exif = exif_read_data($file_path);
if ($exif && is_array($exif)) {
$exif_data = array();
// Camera information
if (!empty($exif['Make'])) {
$exif_data[] = array(
'@type' => 'PropertyValue',
'name' => 'Camera Make',
'value' => $exif['Make']
);
}
if (!empty($exif['Model'])) {
$exif_data[] = array(
'@type' => 'PropertyValue',
'name' => 'Camera Model',
'value' => $exif['Model']
);
}
// Photography settings
if (!empty($exif['ISOSpeedRatings'])) {
$exif_data[] = array(
'@type' => 'PropertyValue',
'name' => 'ISO Speed',
'value' => $exif['ISOSpeedRatings']
);
}
if (!empty($exif['FNumber'])) {
$exif_data[] = array(
'@type' => 'PropertyValue',
'name' => 'F-Number',
'value' => $exif['FNumber']
);
}
if (!empty($exif['ExposureTime'])) {
$exif_data[] = array(
'@type' => 'PropertyValue',
'name' => 'Exposure Time',
'value' => $exif['ExposureTime']
);
}
// GPS information (if location enabled)
if (TigerStyleSEO_Utils::get_option('imageobject_include_location', false)) {
$this->add_gps_info_from_exif($schema, $exif);
}
if (!empty($exif_data)) {
$schema['exifData'] = $exif_data;
}
}
} catch (Exception $e) {
// Silently handle EXIF reading errors
TigerStyleSEO_Utils::debug_log('EXIF reading error', $e->getMessage());
}
}
/**
* Add GPS information from EXIF data
*/
private function add_gps_info_from_exif(&$schema, $exif) {
if (empty($exif['GPSLatitude']) || empty($exif['GPSLongitude'])) {
return;
}
try {
// Convert GPS coordinates
$lat = $this->convert_gps_coordinate($exif['GPSLatitude'], $exif['GPSLatitudeRef']);
$lng = $this->convert_gps_coordinate($exif['GPSLongitude'], $exif['GPSLongitudeRef']);
if ($lat !== null && $lng !== null) {
$schema['contentLocation'] = array(
'@type' => 'Place',
'geo' => array(
'@type' => 'GeoCoordinates',
'latitude' => $lat,
'longitude' => $lng
)
);
}
} catch (Exception $e) {
// Silently handle GPS conversion errors
}
}
/**
* Convert GPS coordinate from EXIF format
*/
private function convert_gps_coordinate($coordinate, $hemisphere) {
if (!is_array($coordinate) || count($coordinate) !== 3) {
return null;
}
$degrees = $this->fraction_to_float($coordinate[0]);
$minutes = $this->fraction_to_float($coordinate[1]);
$seconds = $this->fraction_to_float($coordinate[2]);
$decimal = $degrees + ($minutes / 60) + ($seconds / 3600);
if ($hemisphere === 'S' || $hemisphere === 'W') {
$decimal *= -1;
}
return round($decimal, 6);
}
/**
* Convert fraction string to float
*/
private function fraction_to_float($fraction) {
if (strpos($fraction, '/') !== false) {
$parts = explode('/', $fraction);
return floatval($parts[0]) / floatval($parts[1]);
}
return floatval($fraction);
}
/**
* Generate Product structured data
*/
private function get_product_schema() {
// Check if Product is enabled
if (!TigerStyleSEO_Utils::get_option('product_enabled', false)) {
return null;
}
// Only apply to pages and posts
if (!is_single() && !is_page()) {
return null;
}
// Check if this should be treated as a product page
if (!$this->is_product_page()) {
return null;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'Product'
);
// Add basic product information
global $post;
if ($post) {
// Product name
$custom_name = TigerStyleSEO_Utils::get_option('product_name', '');
$schema['name'] = !empty($custom_name) ? $custom_name : get_the_title();
// Product description
$custom_description = TigerStyleSEO_Utils::get_option('product_description', '');
if (!empty($custom_description)) {
$schema['description'] = $custom_description;
} elseif (!empty($post->post_excerpt)) {
$schema['description'] = wp_strip_all_tags($post->post_excerpt);
} else {
$schema['description'] = wp_strip_all_tags(wp_trim_words($post->post_content, 25));
}
// Product URL
$schema['url'] = get_permalink();
}
// Add product identifiers
$this->add_product_identifiers($schema);
// Add product properties
$this->add_product_properties($schema);
// Add product images
$this->add_product_images($schema);
// Add brand information
$this->add_product_brand($schema);
// Add offers
$this->add_product_offers($schema);
// Add reviews and ratings
$this->add_product_reviews($schema);
// Add additional product details
$this->add_product_details($schema);
return $schema;
}
/**
* Determine if current page should be treated as a product page
*/
private function is_product_page() {
// Manual enable override
$manual_enable = TigerStyleSEO_Utils::get_option('product_manual_enable', false);
if ($manual_enable && (is_page() || is_single())) {
return true;
}
// Auto-detect based on content patterns
$auto_detect = TigerStyleSEO_Utils::get_option('product_auto_detect', false);
if (!$auto_detect) {
return false;
}
global $post;
if (!$post) {
return false;
}
$title = strtolower($post->post_title);
$content = strtolower($post->post_content);
// Product page indicators
$product_indicators = array(
'buy', 'price', 'purchase', 'order', 'shop', 'product',
'sale', 'discount', 'offer', 'deal', 'cost', '$',
'add to cart', 'buy now', 'in stock', 'out of stock',
'sku', 'model', 'brand', 'specification'
);
$indicator_count = 0;
foreach ($product_indicators as $indicator) {
if (strpos($title, $indicator) !== false || strpos($content, $indicator) !== false) {
$indicator_count++;
}
}
// Require at least 2 indicators to avoid false positives
return $indicator_count >= 2;
}
/**
* Add product identifiers (SKU, GTIN, MPN, etc.)
*/
private function add_product_identifiers(&$schema) {
// SKU
$sku = TigerStyleSEO_Utils::get_option('product_sku', '');
if (!empty($sku)) {
$schema['sku'] = $sku;
}
// Product ID
$product_id = TigerStyleSEO_Utils::get_option('product_id', '');
if (!empty($product_id)) {
$schema['productID'] = $product_id;
}
// MPN (Manufacturer Part Number)
$mpn = TigerStyleSEO_Utils::get_option('product_mpn', '');
if (!empty($mpn)) {
$schema['mpn'] = $mpn;
}
// GTIN codes
$gtin8 = TigerStyleSEO_Utils::get_option('product_gtin8', '');
if (!empty($gtin8)) {
$schema['gtin8'] = $gtin8;
}
$gtin12 = TigerStyleSEO_Utils::get_option('product_gtin12', '');
if (!empty($gtin12)) {
$schema['gtin12'] = $gtin12;
}
$gtin13 = TigerStyleSEO_Utils::get_option('product_gtin13', '');
if (!empty($gtin13)) {
$schema['gtin13'] = $gtin13;
}
$gtin14 = TigerStyleSEO_Utils::get_option('product_gtin14', '');
if (!empty($gtin14)) {
$schema['gtin14'] = $gtin14;
}
// Generic GTIN
$gtin = TigerStyleSEO_Utils::get_option('product_gtin', '');
if (!empty($gtin) && empty($schema['gtin8']) && empty($schema['gtin12']) && empty($schema['gtin13']) && empty($schema['gtin14'])) {
$schema['gtin'] = $gtin;
}
}
/**
* Add basic product properties
*/
private function add_product_properties(&$schema) {
// Category
$category = TigerStyleSEO_Utils::get_option('product_category', '');
if (!empty($category)) {
$schema['category'] = $category;
}
// Color
$color = TigerStyleSEO_Utils::get_option('product_color', '');
if (!empty($color)) {
$schema['color'] = $color;
}
// Size
$size = TigerStyleSEO_Utils::get_option('product_size', '');
if (!empty($size)) {
$schema['size'] = $size;
}
// Material
$material = TigerStyleSEO_Utils::get_option('product_material', '');
if (!empty($material)) {
$schema['material'] = $material;
}
// Pattern
$pattern = TigerStyleSEO_Utils::get_option('product_pattern', '');
if (!empty($pattern)) {
$schema['pattern'] = $pattern;
}
// Dimensions
$width = TigerStyleSEO_Utils::get_option('product_width', '');
$height = TigerStyleSEO_Utils::get_option('product_height', '');
$depth = TigerStyleSEO_Utils::get_option('product_depth', '');
$weight = TigerStyleSEO_Utils::get_option('product_weight', '');
if (!empty($width)) {
$schema['width'] = array(
'@type' => 'QuantitativeValue',
'value' => floatval($width),
'unitCode' => TigerStyleSEO_Utils::get_option('product_width_unit', 'CMT')
);
}
if (!empty($height)) {
$schema['height'] = array(
'@type' => 'QuantitativeValue',
'value' => floatval($height),
'unitCode' => TigerStyleSEO_Utils::get_option('product_height_unit', 'CMT')
);
}
if (!empty($depth)) {
$schema['depth'] = array(
'@type' => 'QuantitativeValue',
'value' => floatval($depth),
'unitCode' => TigerStyleSEO_Utils::get_option('product_depth_unit', 'CMT')
);
}
if (!empty($weight)) {
$schema['weight'] = array(
'@type' => 'QuantitativeValue',
'value' => floatval($weight),
'unitCode' => TigerStyleSEO_Utils::get_option('product_weight_unit', 'KGM')
);
}
// Model
$model = TigerStyleSEO_Utils::get_option('product_model', '');
if (!empty($model)) {
$schema['model'] = $model;
}
// Item condition
$condition = TigerStyleSEO_Utils::get_option('product_condition', '');
if (!empty($condition)) {
$schema['itemCondition'] = 'https://schema.org/' . $condition;
}
// Dates
$production_date = TigerStyleSEO_Utils::get_option('product_production_date', '');
if (!empty($production_date)) {
$schema['productionDate'] = date('c', strtotime($production_date));
}
$release_date = TigerStyleSEO_Utils::get_option('product_release_date', '');
if (!empty($release_date)) {
$schema['releaseDate'] = date('c', strtotime($release_date));
}
}
/**
* Add product images
*/
private function add_product_images(&$schema) {
$images = array();
// Custom product images
$custom_images = TigerStyleSEO_Utils::get_option('product_images', '');
if (!empty($custom_images)) {
$image_urls = array_map('trim', explode(',', $custom_images));
foreach ($image_urls as $url) {
if (!empty($url) && filter_var($url, FILTER_VALIDATE_URL)) {
$images[] = $url;
}
}
}
// Featured image as fallback
if (empty($images)) {
global $post;
if ($post) {
$featured_image_id = get_post_thumbnail_id($post->ID);
if ($featured_image_id) {
$featured_url = wp_get_attachment_url($featured_image_id);
if ($featured_url) {
$images[] = $featured_url;
}
}
}
}
if (!empty($images)) {
$schema['image'] = count($images) === 1 ? $images[0] : $images;
}
}
/**
* Add brand information
*/
private function add_product_brand(&$schema) {
$brand_name = TigerStyleSEO_Utils::get_option('product_brand_name', '');
if (!empty($brand_name)) {
$brand = array(
'@type' => 'Brand',
'name' => $brand_name
);
// Brand logo
$brand_logo = TigerStyleSEO_Utils::get_option('product_brand_logo', '');
if (!empty($brand_logo)) {
$brand['logo'] = $brand_logo;
}
$schema['brand'] = $brand;
}
// Manufacturer (if different from brand)
$manufacturer = TigerStyleSEO_Utils::get_option('product_manufacturer', '');
if (!empty($manufacturer)) {
$schema['manufacturer'] = array(
'@type' => 'Organization',
'name' => $manufacturer
);
}
}
/**
* Add product offers
*/
private function add_product_offers(&$schema) {
$price = TigerStyleSEO_Utils::get_option('product_price', '');
$currency = TigerStyleSEO_Utils::get_option('product_currency', 'USD');
if (!empty($price)) {
$offer = array(
'@type' => 'Offer',
'price' => floatval($price),
'priceCurrency' => $currency
);
// Availability
$availability = TigerStyleSEO_Utils::get_option('product_availability', '');
if (!empty($availability)) {
$offer['availability'] = 'https://schema.org/' . $availability;
}
// Price valid until
$price_valid_until = TigerStyleSEO_Utils::get_option('product_price_valid_until', '');
if (!empty($price_valid_until)) {
$offer['priceValidUntil'] = date('c', strtotime($price_valid_until));
}
// Seller
$seller = TigerStyleSEO_Utils::get_option('product_seller', get_bloginfo('name'));
if (!empty($seller)) {
$offer['seller'] = array(
'@type' => 'Organization',
'name' => $seller
);
}
// URL (where to buy)
$buy_url = TigerStyleSEO_Utils::get_option('product_buy_url', '');
if (!empty($buy_url)) {
$offer['url'] = $buy_url;
} else {
$offer['url'] = get_permalink();
}
// Item condition
$condition = TigerStyleSEO_Utils::get_option('product_condition', '');
if (!empty($condition)) {
$offer['itemCondition'] = 'https://schema.org/' . $condition;
}
$schema['offers'] = $offer;
}
}
/**
* Add product reviews and ratings
*/
private function add_product_reviews(&$schema) {
// Aggregate rating
$rating_value = TigerStyleSEO_Utils::get_option('product_rating_value', '');
$rating_count = TigerStyleSEO_Utils::get_option('product_rating_count', '');
$best_rating = TigerStyleSEO_Utils::get_option('product_best_rating', '5');
$worst_rating = TigerStyleSEO_Utils::get_option('product_worst_rating', '1');
if (!empty($rating_value) && !empty($rating_count)) {
$schema['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => floatval($rating_value),
'reviewCount' => intval($rating_count),
'bestRating' => intval($best_rating),
'worstRating' => intval($worst_rating)
);
}
// Individual reviews
$reviews_data = TigerStyleSEO_Utils::get_option('product_reviews', '');
if (!empty($reviews_data)) {
$reviews = array();
$review_lines = array_filter(array_map('trim', explode("\n", $reviews_data)));
foreach ($review_lines as $review_line) {
$parts = array_map('trim', explode('|', $review_line));
if (count($parts) >= 3) {
$review = array(
'@type' => 'Review',
'author' => array(
'@type' => 'Person',
'name' => $parts[0]
),
'reviewRating' => array(
'@type' => 'Rating',
'ratingValue' => floatval($parts[1]),
'bestRating' => intval($best_rating),
'worstRating' => intval($worst_rating)
),
'reviewBody' => $parts[2]
);
// Add date if provided
if (isset($parts[3]) && !empty($parts[3])) {
$review['datePublished'] = date('c', strtotime($parts[3]));
}
$reviews[] = $review;
}
}
if (!empty($reviews)) {
$schema['review'] = $reviews;
}
}
}
/**
* Add additional product details
*/
private function add_product_details(&$schema) {
// Awards
$awards = TigerStyleSEO_Utils::get_option('product_awards', '');
if (!empty($awards)) {
$award_list = array_filter(array_map('trim', explode(',', $awards)));
$schema['award'] = count($award_list) === 1 ? $award_list[0] : $award_list;
}
// Additional properties
$additional_properties = TigerStyleSEO_Utils::get_option('product_additional_properties', '');
if (!empty($additional_properties)) {
$properties = array();
$property_lines = array_filter(array_map('trim', explode("\n", $additional_properties)));
foreach ($property_lines as $property_line) {
$parts = array_map('trim', explode(':', $property_line, 2));
if (count($parts) === 2) {
$properties[] = array(
'@type' => 'PropertyValue',
'name' => $parts[0],
'value' => $parts[1]
);
}
}
if (!empty($properties)) {
$schema['additionalProperty'] = $properties;
}
}
// Audience
$audience = TigerStyleSEO_Utils::get_option('product_audience', '');
if (!empty($audience)) {
$schema['audience'] = array(
'@type' => 'Audience',
'audienceType' => $audience
);
}
// Product highlights
$positive_notes = TigerStyleSEO_Utils::get_option('product_positive_notes', '');
if (!empty($positive_notes)) {
$notes = array_filter(array_map('trim', explode(',', $positive_notes)));
$schema['positiveNotes'] = $notes;
}
$negative_notes = TigerStyleSEO_Utils::get_option('product_negative_notes', '');
if (!empty($negative_notes)) {
$notes = array_filter(array_map('trim', explode(',', $negative_notes)));
$schema['negativeNotes'] = $notes;
}
}
/**
* Generate Article structured data
*/
private function get_article_schema() {
// Check if Article is enabled
if (!TigerStyleSEO_Utils::get_option('article_enabled', false)) {
return null;
}
// Only apply to pages and posts
if (!is_single() && !is_page()) {
return null;
}
// Check if this should be treated as an article
if (!$this->is_article_content()) {
return null;
}
// Determine article type
$article_type = $this->determine_article_type();
$schema = array(
'@context' => 'https://schema.org',
'@type' => $article_type
);
// Add basic article information
global $post;
if ($post) {
// Article headline
$custom_headline = TigerStyleSEO_Utils::get_option('article_headline', '');
$schema['headline'] = !empty($custom_headline) ? $custom_headline : get_the_title();
// Alternative headline
$alt_headline = TigerStyleSEO_Utils::get_option('article_alternative_headline', '');
if (!empty($alt_headline)) {
$schema['alternativeHeadline'] = $alt_headline;
}
// Article body
$schema['articleBody'] = wp_strip_all_tags($post->post_content);
// Article section
$article_section = TigerStyleSEO_Utils::get_option('article_section', '');
if (!empty($article_section)) {
$schema['articleSection'] = $article_section;
} else {
// Auto-detect from categories
$categories = get_the_category();
if (!empty($categories)) {
$schema['articleSection'] = $categories[0]->name;
}
}
// Main entity of page
$schema['mainEntityOfPage'] = array(
'@type' => 'WebPage',
'@id' => get_permalink()
);
// URL
$schema['url'] = get_permalink();
// Publication dates
$schema['datePublished'] = get_the_date('c');
$schema['dateModified'] = get_the_modified_date('c');
}
// Add author information
$this->add_article_author($schema);
// Add publisher information
$this->add_article_publisher($schema);
// Add article images
$this->add_article_images($schema);
// Add word count and reading time
$this->add_article_metrics($schema);
// Add article-type specific properties
$this->add_article_type_properties($schema, $article_type);
// Add tags and keywords
$this->add_article_keywords($schema);
// Add additional article properties
$this->add_article_additional_properties($schema);
return $schema;
}
/**
* Determine if current content should be treated as an article
*/
private function is_article_content() {
// Manual enable override
$manual_enable = TigerStyleSEO_Utils::get_option('article_manual_enable', false);
if ($manual_enable && (is_page() || is_single())) {
return true;
}
// Auto-detect based on content type and patterns
$auto_detect = TigerStyleSEO_Utils::get_option('article_auto_detect', true);
if (!$auto_detect) {
return false;
}
// Check if it's a blog post (single post)
if (is_single()) {
return true;
}
// Check for article-like content on pages
if (is_page()) {
global $post;
if (!$post) {
return false;
}
$content = strtolower($post->post_content);
$title = strtolower($post->post_title);
// Article indicators
$article_indicators = array(
'news', 'article', 'story', 'report', 'analysis',
'opinion', 'editorial', 'blog', 'post', 'guide',
'tutorial', 'review', 'interview', 'feature'
);
foreach ($article_indicators as $indicator) {
if (strpos($title, $indicator) !== false || strpos($content, $indicator) !== false) {
return true;
}
}
// Check minimum word count for article-like content
$word_count = str_word_count(wp_strip_all_tags($post->post_content));
if ($word_count >= 300) {
return true;
}
}
return false;
}
/**
* Determine the appropriate article type
*/
private function determine_article_type() {
// Check manual override
$manual_type = TigerStyleSEO_Utils::get_option('article_type', 'auto');
if ($manual_type !== 'auto') {
return $manual_type;
}
global $post;
if (!$post) {
return 'Article';
}
$title = strtolower($post->post_title);
$content = strtolower($post->post_content);
$categories = get_the_category();
// Check for NewsArticle indicators
$news_indicators = array(
'breaking', 'news', 'report', 'press release', 'announcement',
'update', 'alert', 'bulletin', 'headlines', 'developing'
);
foreach ($news_indicators as $indicator) {
if (strpos($title, $indicator) !== false || strpos($content, $indicator) !== false) {
return 'NewsArticle';
}
}
// Check categories for news
if (!empty($categories)) {
foreach ($categories as $category) {
$cat_name = strtolower($category->name);
if (in_array($cat_name, array('news', 'press', 'announcements', 'updates'))) {
return 'NewsArticle';
}
}
}
// Check for BlogPosting indicators
if (is_single()) {
$blog_indicators = array(
'blog', 'post', 'thoughts', 'opinion', 'personal',
'diary', 'journal', 'update', 'reflection'
);
foreach ($blog_indicators as $indicator) {
if (strpos($title, $indicator) !== false) {
return 'BlogPosting';
}
}
// Default to BlogPosting for single posts
return 'BlogPosting';
}
// Default to Article for pages
return 'Article';
}
/**
* Add author information to article schema
*/
private function add_article_author(&$schema) {
global $post;
// Check for custom author override
$custom_author = TigerStyleSEO_Utils::get_option('article_author_name', '');
if (!empty($custom_author)) {
$author_schema = array(
'@type' => 'Person',
'name' => $custom_author
);
// Add author URL if provided
$author_url = TigerStyleSEO_Utils::get_option('article_author_url', '');
if (!empty($author_url)) {
$author_schema['url'] = $author_url;
}
// Add author description
$author_description = TigerStyleSEO_Utils::get_option('article_author_description', '');
if (!empty($author_description)) {
$author_schema['description'] = $author_description;
}
$schema['author'] = $author_schema;
return;
}
// Use WordPress post author
if ($post) {
$author_id = $post->post_author;
$author = get_userdata($author_id);
if ($author) {
$author_schema = array(
'@type' => 'Person',
'name' => $author->display_name,
'url' => get_author_posts_url($author_id)
);
// Add author description from bio
$author_description = get_user_meta($author_id, 'description', true);
if (!empty($author_description)) {
$author_schema['description'] = $author_description;
}
$schema['author'] = $author_schema;
}
}
}
/**
* Add publisher information to article schema
*/
private function add_article_publisher(&$schema) {
// Check for custom publisher
$custom_publisher = TigerStyleSEO_Utils::get_option('article_publisher_name', '');
if (!empty($custom_publisher)) {
$publisher_schema = array(
'@type' => 'Organization',
'name' => $custom_publisher
);
// Add publisher logo
$publisher_logo = TigerStyleSEO_Utils::get_option('article_publisher_logo', '');
if (!empty($publisher_logo)) {
$publisher_schema['logo'] = array(
'@type' => 'ImageObject',
'url' => $publisher_logo
);
}
// Add publisher URL
$publisher_url = TigerStyleSEO_Utils::get_option('article_publisher_url', '');
if (!empty($publisher_url)) {
$publisher_schema['url'] = $publisher_url;
}
$schema['publisher'] = $publisher_schema;
return;
}
// Use organization data if available
$org_name = TigerStyleSEO_Utils::get_option('organization_name', get_bloginfo('name'));
$org_logo = TigerStyleSEO_Utils::get_option('organization_logo', '');
$publisher_schema = array(
'@type' => 'Organization',
'name' => $org_name,
'url' => home_url()
);
if (!empty($org_logo)) {
$publisher_schema['logo'] = array(
'@type' => 'ImageObject',
'url' => $org_logo
);
}
$schema['publisher'] = $publisher_schema;
}
/**
* Add article images
*/
private function add_article_images(&$schema) {
$images = array();
// Custom article images
$custom_images = TigerStyleSEO_Utils::get_option('article_images', '');
if (!empty($custom_images)) {
$image_urls = array_map('trim', explode(',', $custom_images));
foreach ($image_urls as $url) {
if (!empty($url) && filter_var($url, FILTER_VALIDATE_URL)) {
$images[] = $url;
}
}
}
// Featured image as fallback
if (empty($images)) {
global $post;
if ($post) {
$featured_image_id = get_post_thumbnail_id($post->ID);
if ($featured_image_id) {
$featured_url = wp_get_attachment_url($featured_image_id);
if ($featured_url) {
$images[] = $featured_url;
}
}
}
}
// Auto-extract from content if no images found
if (empty($images) && TigerStyleSEO_Utils::get_option('article_auto_extract_images', true)) {
global $post;
if ($post) {
preg_match_all('/<img[^>]+src=["\']([^"\'\/]+)["\'][^>]*>/i', $post->post_content, $matches);
if (!empty($matches[1])) {
foreach ($matches[1] as $img_src) {
if (filter_var($img_src, FILTER_VALIDATE_URL)) {
$images[] = $img_src;
}
}
}
}
}
if (!empty($images)) {
$schema['image'] = count($images) === 1 ? $images[0] : $images;
}
}
/**
* Add article metrics (word count, reading time)
*/
private function add_article_metrics(&$schema) {
global $post;
if (!$post) {
return;
}
// Word count
$word_count = str_word_count(wp_strip_all_tags($post->post_content));
$schema['wordCount'] = $word_count;
// Estimated reading time (assuming 200 words per minute)
$reading_time = max(1, round($word_count / 200));
$schema['timeRequired'] = 'PT' . $reading_time . 'M';
}
/**
* Add article type-specific properties
*/
private function add_article_type_properties(&$schema, $article_type) {
if ($article_type === 'NewsArticle') {
// News-specific properties
$dateline = TigerStyleSEO_Utils::get_option('article_dateline', '');
if (!empty($dateline)) {
$schema['dateline'] = $dateline;
}
$print_page = TigerStyleSEO_Utils::get_option('article_print_page', '');
if (!empty($print_page)) {
$schema['printPage'] = $print_page;
}
$print_section = TigerStyleSEO_Utils::get_option('article_print_section', '');
if (!empty($print_section)) {
$schema['printSection'] = $print_section;
}
$print_edition = TigerStyleSEO_Utils::get_option('article_print_edition', '');
if (!empty($print_edition)) {
$schema['printEdition'] = $print_edition;
}
$print_column = TigerStyleSEO_Utils::get_option('article_print_column', '');
if (!empty($print_column)) {
$schema['printColumn'] = $print_column;
}
}
if ($article_type === 'BlogPosting') {
// Blog-specific properties
$blog_name = TigerStyleSEO_Utils::get_option('article_blog_name', get_bloginfo('name'));
if (!empty($blog_name)) {
$schema['publisher']['name'] = $blog_name;
}
}
}
/**
* Add article keywords and tags
*/
private function add_article_keywords(&$schema) {
$keywords = array();
// Custom keywords
$custom_keywords = TigerStyleSEO_Utils::get_option('article_keywords', '');
if (!empty($custom_keywords)) {
$custom_array = array_map('trim', explode(',', $custom_keywords));
$keywords = array_merge($keywords, array_filter($custom_array));
}
// Auto-extract from tags
if (TigerStyleSEO_Utils::get_option('article_auto_extract_keywords', true)) {
$tags = get_the_tags();
if (!empty($tags)) {
foreach ($tags as $tag) {
$keywords[] = $tag->name;
}
}
}
if (!empty($keywords)) {
$schema['keywords'] = array_unique($keywords);
}
}
/**
* Add additional article properties
*/
private function add_article_additional_properties(&$schema) {
// Article description
$custom_description = TigerStyleSEO_Utils::get_option('article_description', '');
if (!empty($custom_description)) {
$schema['description'] = $custom_description;
} else {
global $post;
if ($post) {
if (!empty($post->post_excerpt)) {
$schema['description'] = wp_strip_all_tags($post->post_excerpt);
} else {
$schema['description'] = wp_strip_all_tags(wp_trim_words($post->post_content, 25));
}
}
}
// In language
$language = TigerStyleSEO_Utils::get_option('article_language', get_locale());
if (!empty($language)) {
$schema['inLanguage'] = $language;
}
// Copyright year
$copyright_year = TigerStyleSEO_Utils::get_option('article_copyright_year', '');
if (!empty($copyright_year)) {
$schema['copyrightYear'] = intval($copyright_year);
} else {
$schema['copyrightYear'] = intval(get_the_date('Y'));
}
// Copyright holder
$copyright_holder = TigerStyleSEO_Utils::get_option('article_copyright_holder', '');
if (!empty($copyright_holder)) {
$schema['copyrightHolder'] = array(
'@type' => 'Organization',
'name' => $copyright_holder
);
}
// License
$license = TigerStyleSEO_Utils::get_option('article_license', '');
if (!empty($license)) {
$schema['license'] = $license;
}
// Editorial rating
$rating = TigerStyleSEO_Utils::get_option('article_rating', '');
if (!empty($rating)) {
$schema['contentRating'] = $rating;
}
}
}