Last active
July 30, 2026 10:27
-
-
Save pacotole/a71afd4878b61516cd6a94ee5bf5b4f4 to your computer and use it in GitHub Desktop.
Joinchat AI integration with WooCommerce provide product info in markdown to knowlegde base
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: JoinChat AI - WooCommerce Product Enhancement | |
| * Description: Enhances WooCommerce product content for AI knowledge base | |
| * Version: 1.0.0 | |
| * Author: Joinchat | |
| * Author URI: https://join.chat/ | |
| */ | |
| // Prevent direct access | |
| if (!defined('ABSPATH')) { | |
| exit; | |
| } | |
| /** | |
| * Adds structured WooCommerce product information to content for AI | |
| */ | |
| class JoinChatAI_WooCommerce_Enhancement | |
| { | |
| private $current_sync_post_id = null; | |
| public function __construct() | |
| { | |
| // Add product to AI knowledge base CPTs | |
| add_filter('joinchat_ai_cpts', [$this, 'add_product_post_type']); | |
| // Capture post_id from action hook with high priority | |
| add_action('joinchat_schedule_ai_update_post', [$this, 'capture_post_id'], 1); | |
| // Modify content when in KB sync context - low priority to receive filtered content | |
| add_filter('the_content', [$this, 'enhance_product_content'], 999); | |
| } | |
| /** | |
| * Capture post_id from action hook | |
| * | |
| * @param int $post_id The post ID to sync | |
| */ | |
| public function capture_post_id($post_id) | |
| { | |
| $this->current_sync_post_id = $post_id; | |
| } | |
| /** | |
| * Add 'product' to post types for knowledge base | |
| * | |
| * @param array $post_types Current post types | |
| * @return array Modified post types | |
| */ | |
| public function add_product_post_type($post_types) | |
| { | |
| if (!in_array('product', $post_types, true)) { | |
| $post_types[] = 'product'; | |
| } | |
| return $post_types; | |
| } | |
| /** | |
| * Enhance WooCommerce product content with structured information | |
| * | |
| * @param string $content The post content | |
| * @return string The enhanced content | |
| */ | |
| public function enhance_product_content($content) | |
| { | |
| $post_id = $this->current_sync_post_id; | |
| // Verify we have a valid post_id | |
| if (!$post_id) { | |
| return $content; | |
| } | |
| // Verify WooCommerce is active and this is a product | |
| if (!function_exists('wc_get_product') || get_post_type($post_id) !== 'product') { | |
| return $content; | |
| } | |
| $product = wc_get_product($post_id); | |
| if (!$product) { | |
| return $content; | |
| } | |
| // Build AI-optimized markdown | |
| $enhanced_content = $this->build_product_markdown($product, $post_id); | |
| // Add original content after structured markdown | |
| return $enhanced_content . "\n" . $content; | |
| } | |
| /** | |
| * Build structured markdown for product | |
| * | |
| * @param WC_Product $product The WooCommerce product | |
| * @param int $post_id The post ID | |
| * @return string The generated markdown | |
| */ | |
| private function build_product_markdown($product, $post_id) | |
| { | |
| $markdown = []; | |
| $product_name = $product->get_name(); | |
| $product_url = get_permalink($post_id); | |
| $currency_symbol = get_woocommerce_currency_symbol(); | |
| // Product header with link | |
| $markdown[] = ""; | |
| $markdown[] = "# {$product_name}"; | |
| $markdown[] = ""; | |
| $markdown[] = "**Product URL**: {$product_url}"; | |
| $markdown[] = ""; | |
| // Build product introduction sentence | |
| $intro_parts = []; | |
| // Get categories | |
| $categories = wp_get_post_terms($post_id, 'product_cat', ['fields' => 'names']); | |
| if (!empty($categories) && !is_wp_error($categories)) { | |
| $intro_parts[] = implode(' and ', $categories); | |
| } | |
| // Get brand | |
| $brand = $this->get_product_brand($post_id); | |
| if ($brand) { | |
| $intro_parts[] = "from {$brand}"; | |
| } | |
| // Get SKU | |
| if ($product->get_sku()) { | |
| $intro_parts[] = "(SKU: " . $product->get_sku() . ")"; | |
| } | |
| if (!empty($intro_parts)) { | |
| $markdown[] = "This is a " . implode(' ', $intro_parts) . " product."; | |
| $markdown[] = ""; | |
| } | |
| // Product image - placed early for visibility | |
| $image_url = get_the_post_thumbnail_url($post_id, 'large'); | |
| if ($image_url) { | |
| $markdown[] = ""; | |
| $markdown[] = ""; | |
| } | |
| // Short description if available | |
| $short_description = $product->get_short_description(); | |
| if ($short_description) { | |
| $short_description = wp_strip_all_tags($short_description); | |
| $short_description = trim($short_description); | |
| if ($short_description) { | |
| $markdown[] = $short_description; | |
| $markdown[] = ""; | |
| } | |
| } | |
| // Pricing section - conversational format | |
| $markdown[] = "## PRICING AND AVAILABILITY"; | |
| $markdown[] = ""; | |
| $is_variable = $product->is_type('variable'); | |
| $pricing_text = $this->format_pricing_text($product, $currency_symbol, $is_variable); | |
| $markdown[] = $pricing_text; | |
| $markdown[] = ""; | |
| // Stock status | |
| $stock_status = $product->get_stock_status(); | |
| if ($stock_status === 'instock') { | |
| $stock_text = "✅ **Currently in stock**"; | |
| if ($product->managing_stock() && $product->get_stock_quantity() !== null) { | |
| $quantity = $product->get_stock_quantity(); | |
| $stock_text .= " ({$quantity} units available)"; | |
| } | |
| $markdown[] = $stock_text; | |
| // Add direct "Add to cart" link for simple products | |
| if (!$is_variable && $product->is_purchasable()) { | |
| $add_to_cart_url = add_query_arg('add-to-cart', $post_id, wc_get_cart_url()); | |
| $markdown[] = ""; | |
| $markdown[] = "🛒 **[Add to cart]({$add_to_cart_url})**"; | |
| } | |
| } else { | |
| $markdown[] = "❌ **Currently out of stock**"; | |
| } | |
| $markdown[] = ""; | |
| // Product attributes and variations | |
| $attributes = $product->get_attributes(); | |
| if (!empty($attributes)) { | |
| $markdown[] = "## PRODUCT OPTIONS"; | |
| $markdown[] = ""; | |
| $attribute_lines = []; | |
| foreach ($attributes as $attribute) { | |
| if ($attribute->get_visible()) { | |
| $name = wc_attribute_label($attribute->get_name()); | |
| $values = []; | |
| if ($attribute->is_taxonomy()) { | |
| $terms = wp_get_post_terms($post_id, $attribute->get_name(), ['fields' => 'names']); | |
| if (!is_wp_error($terms)) { | |
| $values = $terms; | |
| } | |
| } else { | |
| $values = $attribute->get_options(); | |
| } | |
| if (!empty($values)) { | |
| $attribute_lines[] = "**{$name}**: " . implode(', ', $values); | |
| } | |
| } | |
| } | |
| if (!empty($attribute_lines)) { | |
| $markdown[] = implode(" \n", $attribute_lines); | |
| $markdown[] = ""; | |
| } | |
| } | |
| // Product tags | |
| $tags = wp_get_post_terms($post_id, 'product_tag', ['fields' => 'names']); | |
| if (!empty($tags) && !is_wp_error($tags)) { | |
| $markdown[] = "**Tags**: " . implode(', ', $tags); | |
| $markdown[] = ""; | |
| } | |
| $markdown[] = "---"; | |
| $markdown[] = ""; | |
| return implode("\n", $markdown); | |
| } | |
| /** | |
| * Get product brand from common taxonomies | |
| * | |
| * @param int $post_id The post ID | |
| * @return string|null The brand name or null | |
| */ | |
| private function get_product_brand($post_id) | |
| { | |
| $brand_taxonomies = ['product_brand', 'pwb-brand', 'yith_product_brand', 'brand']; | |
| foreach ($brand_taxonomies as $taxonomy) { | |
| if (taxonomy_exists($taxonomy)) { | |
| $brands = wp_get_post_terms($post_id, $taxonomy, ['fields' => 'names']); | |
| if (!empty($brands) && !is_wp_error($brands)) { | |
| return implode(', ', $brands); | |
| } | |
| } | |
| } | |
| return null; | |
| } | |
| /** | |
| * Format pricing text in conversational style | |
| * | |
| * @param WC_Product $product The product | |
| * @param string $currency_symbol Currency symbol | |
| * @param bool $is_variable Whether product is variable | |
| * @return string Formatted pricing text | |
| */ | |
| private function format_pricing_text($product, $currency_symbol, $is_variable) | |
| { | |
| if ($is_variable) { | |
| $min_regular = $product->get_variation_regular_price('min'); | |
| $max_regular = $product->get_variation_regular_price('max'); | |
| $min_sale = $product->get_variation_sale_price('min'); | |
| $max_sale = $product->get_variation_sale_price('max'); | |
| if ($product->is_on_sale()) { | |
| $price_range = $min_sale === $max_sale | |
| ? "{$currency_symbol}{$min_sale}" | |
| : "{$currency_symbol}{$min_sale} - {$currency_symbol}{$max_sale}"; | |
| $regular_range = $min_regular === $max_regular | |
| ? "{$currency_symbol}{$min_regular}" | |
| : "{$currency_symbol}{$min_regular} - {$currency_symbol}{$max_regular}"; | |
| $discount = round((($max_regular - $min_sale) / $max_regular) * 100); | |
| return "🏷️ **ON SALE** - Price: **{$price_range}** (Regular price: {$regular_range}, save up to {$discount}%)"; | |
| } else { | |
| $price_range = $min_regular === $max_regular | |
| ? "{$currency_symbol}{$min_regular}" | |
| : "{$currency_symbol}{$min_regular} - {$currency_symbol}{$max_regular}"; | |
| return "Price: **{$price_range}**"; | |
| } | |
| } else { | |
| // Simple product | |
| if ($product->is_on_sale()) { | |
| $regular = $product->get_regular_price(); | |
| $sale = $product->get_sale_price(); | |
| $discount = round((($regular - $sale) / $regular) * 100); | |
| return "🏷️ **ON SALE** - Price: **{$currency_symbol}{$sale}** (Regular price: {$currency_symbol}{$regular}, save {$discount}%)"; | |
| } else { | |
| $price = $product->get_regular_price(); | |
| return "Price: **{$currency_symbol}{$price}**"; | |
| } | |
| } | |
| } | |
| } | |
| // Initialize the enhancement | |
| new JoinChatAI_WooCommerce_Enhancement(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment