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\n"; foreach ($structured_data as $schema) { echo '' . "\n"; } echo "\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\n"; echo '' . "\n"; echo "\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('/]*>.*?]+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('/]+>/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('/]+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; } } }