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.
3059 lines
119 KiB
PHP
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;
|
|
}
|
|
}
|
|
} |