Last active
July 10, 2024 11:28
-
-
Save ajlowndes/7b7ba278815051c9d5a9b3b75e5d7dc9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /* | |
| Plugin Name: WooCommerce Schema.org Course Data | |
| Description: Adds schema.org course and courseInstance data to WooCommerce products | |
| Version: 1.3 | |
| Author: Aaron Lowndes | |
| */ | |
| if (!defined('ABSPATH')) exit; // Exit if accessed directly | |
| class WC_Schema_Course_Data { | |
| public function __construct() { | |
| add_action('woocommerce_after_single_product', array($this, 'output_schema_data')); | |
| } | |
| public function output_schema_data() { | |
| global $product; | |
| if (!$this->is_course($product)) return; | |
| $schema = array( | |
| '@context' => 'https://schema.org', | |
| '@type' => 'Course', | |
| 'name' => $product->get_name(), | |
| 'description' => $product->get_short_description(), | |
| 'provider' => array( | |
| '@type' => 'Organization', | |
| 'name' => 'Melbourne Climbing School', | |
| 'url' => home_url() | |
| ), | |
| 'offers' => $this->get_course_offers($product), | |
| 'hasCourseInstance' => $this->get_course_instances($product) | |
| ); | |
| echo '<script type="application/ld+json">' . json_encode($schema) . '</script>'; | |
| } | |
| private function is_course($product) { | |
| return $product->get_type() == 'registrations'; | |
| } | |
| private function get_course_offers($product) { | |
| return array( | |
| '@type' => 'Offer', | |
| 'price' => $product->get_price(), | |
| 'priceCurrency' => get_woocommerce_currency(), | |
| 'availability' => $product->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock', | |
| 'url' => get_permalink($product->get_id()), | |
| 'category' => $this->get_product_category($product), | |
| 'hasMerchantReturnPolicy' => array( | |
| '@type' => 'MerchantReturnPolicy', | |
| 'applicableCountry' => 'AU', | |
| 'returnPolicyCategory' => 'https://schema.org/MerchantReturnFiniteReturnWindow', | |
| 'returnWindow' => array( | |
| '@type' => 'MonetaryAmount', | |
| 'value' => '7', | |
| 'unitCode' => 'DAY' | |
| ), | |
| 'refundType' => 'https://schema.org/PartialRefund', | |
| 'returnMethod' => 'https://schema.org/ReturnAtKiosk' | |
| ) | |
| ); | |
| } | |
| private function get_product_category($product) { | |
| $categories = get_the_terms($product->get_id(), 'product_cat'); | |
| if ($categories && !is_wp_error($categories)) { | |
| return $categories[0]->name; | |
| } | |
| return 'Climbing Course'; // Default category if none is set | |
| } | |
| private function get_course_instances($product) { | |
| $instances = array(); | |
| $variations = $product->get_children(); | |
| foreach ($variations as $variation_id) { | |
| $variation = wc_get_product($variation_id); | |
| $variation_data = $variation->get_data(); | |
| $instance = array( | |
| '@type' => 'CourseInstance', | |
| 'name' => $variation->get_name(), | |
| 'url' => $variation->get_permalink(), | |
| 'sku' => $variation->get_sku(), | |
| 'description' => $variation->get_description(), | |
| 'courseMode' => ['onsite'], | |
| 'eventAttendanceMode' => 'https://schema.org/OfflineEventAttendanceMode', | |
| 'courseWorkload' => 'PT8H', // Assumes 8 hours per day, modify as needed | |
| 'offers' => array( | |
| '@type' => 'Offer', | |
| 'price' => $variation->get_price(), | |
| 'priceCurrency' => get_woocommerce_currency(), | |
| 'availability' => $variation->is_in_stock() ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock', | |
| 'url' => $variation->get_permalink(), | |
| 'category' => $this->get_product_category($product) | |
| ) | |
| ); | |
| // Extract dates from attributes | |
| $attributes = $variation->get_attributes(); | |
| if (isset($attributes['dates'])) { | |
| $dates_json = $attributes['dates']; | |
| $dates_data = json_decode($dates_json, true); | |
| if ($dates_data && isset($dates_data['dates']) && is_array($dates_data['dates']) && !empty($dates_data['dates'])) { | |
| $start_date = $dates_data['dates'][0]; // First date in the array | |
| $end_date = end($dates_data['dates']); // Last date in the array | |
| // Get start and end times from meta data | |
| $start_time = $variation->get_meta('_event_start_time', true) ?: '09:00'; | |
| $end_time = $variation->get_meta('_event_end_time', true) ?: '17:00'; | |
| // Combine dates and times | |
| $instance['startDate'] = date('c', strtotime("$start_date $start_time")); | |
| $instance['endDate'] = date('c', strtotime("$end_date $end_time")); | |
| } | |
| } | |
| // Add course schedule based on SKU | |
| if ($variation->get_sku() === 'ltl') { | |
| $instance['courseSchedule'] = '6:30 PM to 9:30 PM each day'; | |
| } else { | |
| $instance['courseSchedule'] = '9:00 AM to 5:00 PM each day'; | |
| } | |
| // Add image | |
| $image_id = $variation->get_image_id(); | |
| $image_array = wp_get_attachment_image_src($image_id, array('500','500'), true); | |
| if ($image_array) { | |
| $instance['image'] = $image_array[0]; | |
| } | |
| // Add location | |
| $location_name = $variation->get_meta('location_name', true); | |
| if ($location_name) { | |
| $instance['location'] = array( | |
| '@type' => 'Place', | |
| 'name' => $location_name | |
| ); | |
| } | |
| $instances[] = $instance; | |
| } | |
| return $instances; | |
| } | |
| private function format_datetime($datetime) { | |
| // Convert to ISO 8601 format | |
| return date('c', strtotime($datetime)); | |
| } | |
| } | |
| new WC_Schema_Course_Data(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment