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

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

564 lines
22 KiB
PHP

<?php
/**
* OpenGraph Module for TigerStyle Heat
* Implements Facebook OpenGraph meta tags for social sharing optimization
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
class TigerStyleSEO_OpenGraph {
/**
* 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_opengraph_tags'), 5);
// Admin hooks
if (is_admin()) {
add_action('admin_post_update_opengraph_settings', array($this, 'handle_form_submission'));
}
}
/**
* Inject OpenGraph meta tags into head section
*/
public function inject_opengraph_tags() {
$settings = $this->get_opengraph_settings();
if (!$settings['enabled']) {
return;
}
$tags = $this->generate_opengraph_tags();
if (!empty($tags)) {
echo "\n<!-- TigerStyle Heat - OpenGraph Meta Tags -->\n";
foreach ($tags as $tag) {
echo $tag . "\n";
}
echo "<!-- End TigerStyle Heat OpenGraph -->\n\n";
}
}
/**
* Generate OpenGraph meta tags based on current page
*/
private function generate_opengraph_tags() {
$tags = array();
$settings = $this->get_opengraph_settings();
// Required tags
$tags[] = '<meta property="og:url" content="' . esc_attr($this->get_canonical_url()) . '" />';
$tags[] = '<meta property="og:title" content="' . esc_attr($this->get_page_title()) . '" />';
$tags[] = '<meta property="og:description" content="' . esc_attr($this->get_page_description()) . '" />';
$tags[] = '<meta property="og:image" content="' . esc_attr($this->get_page_image()) . '" />';
// Optional but recommended tags
$tags[] = '<meta property="og:type" content="' . esc_attr($this->get_page_type()) . '" />';
$tags[] = '<meta property="og:locale" content="' . esc_attr($this->get_locale()) . '" />';
// Site name
if (!empty($settings['site_name'])) {
$tags[] = '<meta property="og:site_name" content="' . esc_attr($settings['site_name']) . '" />';
}
// Facebook App ID
if (!empty($settings['app_id'])) {
$tags[] = '<meta property="fb:app_id" content="' . esc_attr($settings['app_id']) . '" />';
}
// Image dimensions if available
$image_data = $this->get_image_data($this->get_page_image());
if ($image_data) {
$tags[] = '<meta property="og:image:width" content="' . esc_attr($image_data['width']) . '" />';
$tags[] = '<meta property="og:image:height" content="' . esc_attr($image_data['height']) . '" />';
if (!empty($image_data['type'])) {
$tags[] = '<meta property="og:image:type" content="' . esc_attr($image_data['type']) . '" />';
}
}
// Article-specific tags for posts
if (is_single() && get_post_type() === 'post') {
$post = get_post();
$tags[] = '<meta property="article:published_time" content="' . esc_attr(get_the_date('c')) . '" />';
$tags[] = '<meta property="article:modified_time" content="' . esc_attr(get_the_modified_date('c')) . '" />';
// Author
$author = get_the_author_meta('display_name', $post->post_author);
if ($author) {
$tags[] = '<meta property="article:author" content="' . esc_attr($author) . '" />';
}
// Categories as sections
$categories = get_the_category();
foreach ($categories as $category) {
$tags[] = '<meta property="article:section" content="' . esc_attr($category->name) . '" />';
}
// Tags
$post_tags = get_the_tags();
if ($post_tags) {
foreach ($post_tags as $tag) {
$tags[] = '<meta property="article:tag" content="' . esc_attr($tag->name) . '" />';
}
}
}
return apply_filters('tigerstyle_heat_opengraph_tags', $tags);
}
/**
* Get canonical URL for current page
*/
private function get_canonical_url() {
if (is_home() || is_front_page()) {
return home_url('/');
}
if (is_singular()) {
return get_permalink();
}
if (is_category()) {
return get_category_link(get_queried_object_id());
}
if (is_tag()) {
return get_tag_link(get_queried_object_id());
}
if (is_author()) {
return get_author_posts_url(get_queried_object_id());
}
// Fallback to current URL
global $wp;
return home_url(add_query_arg(array(), $wp->request));
}
/**
* Get page title optimized for social sharing
*/
private function get_page_title() {
if (is_singular()) {
return get_the_title();
}
if (is_home() || is_front_page()) {
return get_bloginfo('name');
}
if (is_category()) {
return single_cat_title('', false);
}
if (is_tag()) {
return single_tag_title('', false);
}
if (is_author()) {
return get_the_author_meta('display_name', get_queried_object_id());
}
if (is_archive()) {
return get_the_archive_title();
}
return get_bloginfo('name');
}
/**
* Get page description for social sharing
*/
private function get_page_description() {
$settings = $this->get_opengraph_settings();
if (is_singular()) {
$post = get_post();
// Try excerpt first
if (!empty($post->post_excerpt)) {
return wp_strip_all_tags($post->post_excerpt);
}
// Try content excerpt
$content = wp_strip_all_tags($post->post_content);
if ($content) {
return wp_trim_words($content, 30);
}
}
if (is_category()) {
$description = category_description();
if ($description) {
return wp_strip_all_tags($description);
}
}
if (is_tag()) {
$description = tag_description();
if ($description) {
return wp_strip_all_tags($description);
}
}
// Fallback to site description
return get_bloginfo('description') ?: $settings['default_description'];
}
/**
* Get appropriate image for the page
*/
private function get_page_image() {
$settings = $this->get_opengraph_settings();
// Featured image for posts/pages
if (is_singular() && has_post_thumbnail()) {
$image_id = get_post_thumbnail_id();
$image_url = wp_get_attachment_image_url($image_id, 'large');
if ($image_url) {
return $image_url;
}
}
// Find first image in content
if (is_singular()) {
$content = get_post_field('post_content');
preg_match('/<img[^>]+src="([^">]+)"/', $content, $matches);
if (!empty($matches[1])) {
return $matches[1];
}
}
// Default image from settings
if (!empty($settings['default_image'])) {
return $settings['default_image'];
}
// Site logo as fallback
$custom_logo_id = get_theme_mod('custom_logo');
if ($custom_logo_id) {
$logo_url = wp_get_attachment_image_url($custom_logo_id, 'large');
if ($logo_url) {
return $logo_url;
}
}
return '';
}
/**
* Get OpenGraph type for current page
*/
private function get_page_type() {
if (is_single() && get_post_type() === 'post') {
return 'article';
}
if (is_page()) {
return 'website';
}
if (is_author()) {
return 'profile';
}
return 'website';
}
/**
* Get locale for OpenGraph
*/
private function get_locale() {
$locale = get_locale();
// Convert WordPress locale to OpenGraph format
$locale_map = array(
'en_US' => 'en_US',
'en_GB' => 'en_GB',
'es_ES' => 'es_ES',
'fr_FR' => 'fr_FR',
'de_DE' => 'de_DE',
'it_IT' => 'it_IT',
'pt_BR' => 'pt_BR',
'nl_NL' => 'nl_NL',
'ru_RU' => 'ru_RU',
'ja' => 'ja_JP',
'zh_CN' => 'zh_CN',
);
return isset($locale_map[$locale]) ? $locale_map[$locale] : 'en_US';
}
/**
* Get image dimensions and type
*/
private function get_image_data($image_url) {
if (empty($image_url)) {
return false;
}
// Try to get attachment ID from URL
$attachment_id = attachment_url_to_postid($image_url);
if ($attachment_id) {
$metadata = wp_get_attachment_metadata($attachment_id);
if ($metadata && isset($metadata['width'], $metadata['height'])) {
return array(
'width' => $metadata['width'],
'height' => $metadata['height'],
'type' => get_post_mime_type($attachment_id)
);
}
}
// Try to get image size from URL (if local)
if (strpos($image_url, home_url()) === 0) {
$upload_dir = wp_upload_dir();
$image_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $image_url);
if (file_exists($image_path)) {
$image_info = getimagesize($image_path);
if ($image_info) {
return array(
'width' => $image_info[0],
'height' => $image_info[1],
'type' => $image_info['mime']
);
}
}
}
return false;
}
/**
* Get OpenGraph settings
*/
private function get_opengraph_settings() {
$defaults = array(
'enabled' => true,
'site_name' => get_bloginfo('name'),
'app_id' => '',
'default_description' => get_bloginfo('description'),
'default_image' => '',
'include_article_tags' => true,
'include_author_info' => true
);
$settings = get_option('tigerstyle_opengraph_settings', array());
return wp_parse_args($settings, $defaults);
}
/**
* Handle form submission
*/
public function handle_form_submission() {
if (!current_user_can('manage_options')) {
wp_die(__('You do not have sufficient permissions to access this page.'));
}
if (!wp_verify_nonce($_POST['_wpnonce'], 'tigerstyle_opengraph_settings')) {
wp_die(__('Security check failed. Please try again.'));
}
$settings = array(
'enabled' => isset($_POST['og_enabled']) ? 1 : 0,
'site_name' => sanitize_text_field($_POST['og_site_name'] ?? ''),
'app_id' => sanitize_text_field($_POST['og_app_id'] ?? ''),
'default_description' => sanitize_textarea_field($_POST['og_default_description'] ?? ''),
'default_image' => esc_url_raw($_POST['og_default_image'] ?? ''),
'include_article_tags' => isset($_POST['og_include_article_tags']) ? 1 : 0,
'include_author_info' => isset($_POST['og_include_author_info']) ? 1 : 0
);
update_option('tigerstyle_opengraph_settings', $settings);
wp_redirect(add_query_arg(array('page' => 'tigerstyle-heat', 'tab' => 'opengraph', 'updated' => 'true'), admin_url('admin.php')));
exit;
}
/**
* Get debug information for current page
*/
public function get_debug_info() {
if (!current_user_can('manage_options')) {
return array();
}
return array(
'url' => $this->get_canonical_url(),
'title' => $this->get_page_title(),
'description' => $this->get_page_description(),
'image' => $this->get_page_image(),
'type' => $this->get_page_type(),
'locale' => $this->get_locale(),
'tags' => $this->generate_opengraph_tags()
);
}
/**
* Render admin page
*/
public function render_admin_page() {
$settings = $this->get_opengraph_settings();
?>
<div class="seo-info-box">
<h2><?php _e('Facebook OpenGraph Configuration', 'tigerstyle-heat'); ?></h2>
<p><?php _e('Configure OpenGraph meta tags to optimize how your content appears when shared on Facebook, LinkedIn, Twitter, and other social platforms.', 'tigerstyle-heat'); ?></p>
<div class="seo-setup-steps">
<h3><?php _e('What is OpenGraph?', 'tigerstyle-heat'); ?></h3>
<p><?php _e('OpenGraph is a protocol that enables any web page to become a rich object in a social graph. It allows you to control how your content appears when shared on social media platforms.', 'tigerstyle-heat'); ?></p>
<h4><?php _e('Key OpenGraph Meta Tags:', 'tigerstyle-heat'); ?></h4>
<ul>
<li><strong>og:title</strong> - <?php _e('The title of your content', 'tigerstyle-heat'); ?></li>
<li><strong>og:description</strong> - <?php _e('A brief description of your content', 'tigerstyle-heat'); ?></li>
<li><strong>og:image</strong> - <?php _e('An image representing your content', 'tigerstyle-heat'); ?></li>
<li><strong>og:url</strong> - <?php _e('The canonical URL of your content', 'tigerstyle-heat'); ?></li>
<li><strong>og:type</strong> - <?php _e('The type of object (article, website, etc.)', 'tigerstyle-heat'); ?></li>
</ul>
<p><a href="https://developers.facebook.com/docs/sharing/webmasters/" target="_blank"><?php _e('Learn more about OpenGraph protocol', 'tigerstyle-heat'); ?></a></p>
</div>
</div>
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<?php wp_nonce_field('tigerstyle_opengraph_settings'); ?>
<input type="hidden" name="action" value="update_opengraph_settings">
<table class="form-table">
<tr>
<th scope="row"><?php _e('Enable OpenGraph', 'tigerstyle-heat'); ?></th>
<td>
<label>
<input type="checkbox" name="og_enabled" value="1" <?php checked($settings['enabled']); ?>>
<?php _e('Enable OpenGraph meta tags', 'tigerstyle-heat'); ?>
</label>
<p class="description"><?php _e('Enable automatic generation of OpenGraph meta tags for social sharing.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Site Name', 'tigerstyle-heat'); ?></th>
<td>
<input type="text" name="og_site_name" value="<?php echo esc_attr($settings['site_name']); ?>" class="regular-text">
<p class="description"><?php _e('The name of your website. Defaults to site title.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Facebook App ID', 'tigerstyle-heat'); ?></th>
<td>
<input type="text" name="og_app_id" value="<?php echo esc_attr($settings['app_id']); ?>" class="regular-text">
<p class="description"><?php _e('Optional: Your Facebook App ID for enhanced social insights.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Default Description', 'tigerstyle-heat'); ?></th>
<td>
<textarea name="og_default_description" rows="3" class="large-text"><?php echo esc_textarea($settings['default_description']); ?></textarea>
<p class="description"><?php _e('Default description used when no specific content description is available.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Default Image URL', 'tigerstyle-heat'); ?></th>
<td>
<input type="url" name="og_default_image" value="<?php echo esc_attr($settings['default_image']); ?>" class="large-text">
<p class="description"><?php _e('Default image used when no featured image is available. Recommended size: 1200x630 pixels.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Article Options', 'tigerstyle-heat'); ?></th>
<td>
<label>
<input type="checkbox" name="og_include_article_tags" value="1" <?php checked($settings['include_article_tags']); ?>>
<?php _e('Include article tags and categories', 'tigerstyle-heat'); ?>
</label>
<br>
<label>
<input type="checkbox" name="og_include_author_info" value="1" <?php checked($settings['include_author_info']); ?>>
<?php _e('Include article author information', 'tigerstyle-heat'); ?>
</label>
<p class="description"><?php _e('Enhanced metadata for blog posts and articles.', 'tigerstyle-heat'); ?></p>
</td>
</tr>
</table>
<?php submit_button(__('Save OpenGraph Settings', 'tigerstyle-heat')); ?>
</form>
<?php if ($settings['enabled'] && current_user_can('manage_options')): ?>
<div class="seo-info-box">
<h3><?php _e('Current Page OpenGraph Preview', 'tigerstyle-heat'); ?></h3>
<p><?php _e('Preview how the current page would appear with OpenGraph tags:', 'tigerstyle-heat'); ?></p>
<?php
$debug_info = $this->get_debug_info();
if (!empty($debug_info)):
?>
<div style="border: 1px solid #ddd; padding: 15px; margin: 15px 0; background: #f9f9f9;">
<h4><?php _e('OpenGraph Data:', 'tigerstyle-heat'); ?></h4>
<p><strong><?php _e('Title:', 'tigerstyle-heat'); ?></strong> <?php echo esc_html($debug_info['title']); ?></p>
<p><strong><?php _e('Description:', 'tigerstyle-heat'); ?></strong> <?php echo esc_html($debug_info['description']); ?></p>
<p><strong><?php _e('URL:', 'tigerstyle-heat'); ?></strong> <?php echo esc_html($debug_info['url']); ?></p>
<p><strong><?php _e('Type:', 'tigerstyle-heat'); ?></strong> <?php echo esc_html($debug_info['type']); ?></p>
<?php if (!empty($debug_info['image'])): ?>
<p><strong><?php _e('Image:', 'tigerstyle-heat'); ?></strong> <br>
<img src="<?php echo esc_url($debug_info['image']); ?>" style="max-width: 300px; max-height: 150px; border: 1px solid #ddd;" alt="OpenGraph Preview">
</p>
<?php endif; ?>
<h4><?php _e('Generated Meta Tags:', 'tigerstyle-heat'); ?></h4>
<pre style="background: #f0f0f0; padding: 10px; overflow-x: auto; font-size: 12px;"><?php
foreach ($debug_info['tags'] as $tag) {
echo esc_html($tag) . "\n";
}
?></pre>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="seo-info-box">
<h3><?php _e('Testing Your OpenGraph Tags', 'tigerstyle-heat'); ?></h3>
<p><?php _e('Use these tools to validate and preview your OpenGraph implementation:', 'tigerstyle-heat'); ?></p>
<ul>
<li><a href="https://developers.facebook.com/tools/debug/" target="_blank"><?php _e('Facebook Sharing Debugger', 'tigerstyle-heat'); ?></a></li>
<li><a href="https://www.linkedin.com/post-inspector/" target="_blank"><?php _e('LinkedIn Post Inspector', 'tigerstyle-heat'); ?></a></li>
<li><a href="https://cards-dev.twitter.com/validator" target="_blank"><?php _e('Twitter Card Validator', 'tigerstyle-heat'); ?></a></li>
</ul>
</div>
<?php
}
}