Phase 5: Content and SEO - Yoast SEO, Schema.org markup, Open Graph, favicon support, XML sitemap
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user