Phase 5: Content and SEO - Yoast SEO, Schema.org markup, Open Graph, favicon support, XML sitemap

This commit is contained in:
Hanson.xyz Dev
2025-11-28 17:10:24 -06:00
parent c4f29a3152
commit 91de533da4
1552 changed files with 171432 additions and 7 deletions
+3
View File
@@ -37,3 +37,6 @@ require_once HOMEPROZ_DIR . '/inc/acf-fields.php';
// AJAX handlers
require_once HOMEPROZ_DIR . '/inc/ajax-handlers.php';
// Schema.org structured data
require_once HOMEPROZ_DIR . '/inc/schema-markup.php';
@@ -0,0 +1,277 @@
<?php
/**
* Schema.org Structured Data Markup
*
* @package HomeProz
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
/**
* Output LocalBusiness schema on all pages
*/
function homeproz_local_business_schema() {
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'RealEstateAgent',
'@id' => home_url('/#organization'),
'name' => 'HomeProz Real Estate',
'description' => 'Your trusted partner for buying and selling homes in Albert Lea, Minnesota and surrounding areas.',
'url' => home_url('/'),
'logo' => array(
'@type' => 'ImageObject',
'url' => HOMEPROZ_URI . '/assets/images/logo.png',
),
'image' => HOMEPROZ_URI . '/assets/images/logo.png',
'telephone' => '+1-507-383-2048',
'email' => 'contact@homeprozrealestate.com',
'address' => array(
'@type' => 'PostalAddress',
'streetAddress' => '113 E Clark St',
'addressLocality' => 'Albert Lea',
'addressRegion' => 'MN',
'postalCode' => '56007',
'addressCountry' => 'US',
),
'geo' => array(
'@type' => 'GeoCoordinates',
'latitude' => 43.6477,
'longitude' => -93.3683,
),
'areaServed' => array(
'@type' => 'GeoCircle',
'geoMidpoint' => array(
'@type' => 'GeoCoordinates',
'latitude' => 43.6477,
'longitude' => -93.3683,
),
'geoRadius' => '50000',
),
'openingHoursSpecification' => array(
array(
'@type' => 'OpeningHoursSpecification',
'dayOfWeek' => array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'),
'opens' => '09:00',
'closes' => '17:00',
),
),
'sameAs' => array(
'https://www.facebook.com/homeprozrealestate',
),
);
echo '<script type="application/ld+json">' . wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . '</script>' . "\n";
}
add_action('wp_head', 'homeproz_local_business_schema', 5);
/**
* Output RealEstateListing schema on single property pages
*/
function homeproz_property_schema() {
if (!is_singular('property')) {
return;
}
$post_id = get_the_ID();
// Get property fields
$price = get_field('price', $post_id);
$status = get_field('property_status', $post_id);
$property_type = get_field('property_type', $post_id);
$bedrooms = get_field('bedrooms', $post_id);
$bathrooms = get_field('bathrooms', $post_id);
$square_feet = get_field('square_feet', $post_id);
$street_address = get_field('street_address', $post_id);
$city = get_field('city', $post_id);
$state = get_field('state', $post_id);
$zip_code = get_field('zip_code', $post_id);
$short_description = get_field('short_description', $post_id);
// Get featured image
$image_url = '';
if (has_post_thumbnail($post_id)) {
$image_url = get_the_post_thumbnail_url($post_id, 'large');
}
// Map status to schema offer status
$availability = 'https://schema.org/InStock';
if ($status === 'sold') {
$availability = 'https://schema.org/SoldOut';
} elseif ($status === 'pending') {
$availability = 'https://schema.org/PreOrder';
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'RealEstateListing',
'@id' => get_permalink($post_id),
'name' => get_the_title($post_id),
'description' => $short_description ?: get_the_excerpt($post_id),
'url' => get_permalink($post_id),
'datePosted' => get_the_date('c', $post_id),
'image' => $image_url,
'offers' => array(
'@type' => 'Offer',
'price' => $price ? (float) $price : 0,
'priceCurrency' => 'USD',
'availability' => $availability,
),
);
// Add address if available
if ($street_address || $city) {
$schema['address'] = array(
'@type' => 'PostalAddress',
'streetAddress' => $street_address ?: '',
'addressLocality' => $city ?: 'Albert Lea',
'addressRegion' => $state ?: 'MN',
'postalCode' => $zip_code ?: '',
'addressCountry' => 'US',
);
}
// Add property details if available
if ($bedrooms || $bathrooms || $square_feet) {
$schema['additionalProperty'] = array();
if ($bedrooms) {
$schema['additionalProperty'][] = array(
'@type' => 'PropertyValue',
'name' => 'numberOfBedrooms',
'value' => (int) $bedrooms,
);
}
if ($bathrooms) {
$schema['additionalProperty'][] = array(
'@type' => 'PropertyValue',
'name' => 'numberOfBathroomsTotal',
'value' => (float) $bathrooms,
);
}
if ($square_feet) {
$schema['additionalProperty'][] = array(
'@type' => 'PropertyValue',
'name' => 'floorSize',
'value' => (int) $square_feet,
'unitCode' => 'FTK',
);
}
}
echo '<script type="application/ld+json">' . wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . '</script>' . "\n";
}
add_action('wp_head', 'homeproz_property_schema', 6);
/**
* Output WebSite schema for sitewide search
*/
function homeproz_website_schema() {
if (!is_front_page()) {
return;
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'WebSite',
'@id' => home_url('/#website'),
'name' => get_bloginfo('name'),
'url' => home_url('/'),
'publisher' => array(
'@id' => home_url('/#organization'),
),
'potentialAction' => array(
'@type' => 'SearchAction',
'target' => array(
'@type' => 'EntryPoint',
'urlTemplate' => home_url('/?s={search_term_string}'),
),
'query-input' => 'required name=search_term_string',
),
);
echo '<script type="application/ld+json">' . wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . '</script>' . "\n";
}
add_action('wp_head', 'homeproz_website_schema', 7);
/**
* Output BreadcrumbList schema
*/
function homeproz_breadcrumb_schema() {
if (is_front_page()) {
return;
}
$breadcrumbs = array(
array(
'@type' => 'ListItem',
'position' => 1,
'name' => 'Home',
'item' => home_url('/'),
),
);
$position = 2;
if (is_singular('property')) {
$breadcrumbs[] = array(
'@type' => 'ListItem',
'position' => $position++,
'name' => 'Properties',
'item' => get_post_type_archive_link('property'),
);
$breadcrumbs[] = array(
'@type' => 'ListItem',
'position' => $position,
'name' => get_the_title(),
'item' => get_permalink(),
);
} elseif (is_post_type_archive('property')) {
$breadcrumbs[] = array(
'@type' => 'ListItem',
'position' => $position,
'name' => 'Properties',
'item' => get_post_type_archive_link('property'),
);
} elseif (is_singular('post')) {
$breadcrumbs[] = array(
'@type' => 'ListItem',
'position' => $position++,
'name' => 'Blog',
'item' => get_permalink(get_option('page_for_posts')),
);
$breadcrumbs[] = array(
'@type' => 'ListItem',
'position' => $position,
'name' => get_the_title(),
'item' => get_permalink(),
);
} elseif (is_page()) {
$breadcrumbs[] = array(
'@type' => 'ListItem',
'position' => $position,
'name' => get_the_title(),
'item' => get_permalink(),
);
} elseif (is_home()) {
$breadcrumbs[] = array(
'@type' => 'ListItem',
'position' => $position,
'name' => 'Blog',
'item' => get_permalink(get_option('page_for_posts')),
);
}
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => $breadcrumbs,
);
echo '<script type="application/ld+json">' . wp_json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . '</script>' . "\n";
}
add_action('wp_head', 'homeproz_breadcrumb_schema', 8);
@@ -62,11 +62,23 @@ function homeproz_setup() {
'flex-width' => true,
));
// Add support for site icon (favicon) via Customizer
add_theme_support('site-icon');
// Disable core block patterns (we'll add our own)
remove_theme_support('core-block-patterns');
}
add_action('after_setup_theme', 'homeproz_setup');
/**
* Add theme color meta tag for mobile browsers
*/
function homeproz_theme_color_meta() {
echo '<meta name="theme-color" content="#0A0A0A">' . "\n";
echo '<meta name="msapplication-TileColor" content="#0A0A0A">' . "\n";
}
add_action('wp_head', 'homeproz_theme_color_meta', 1);
/**
* Register custom block pattern category
*/