fieldSlug = $slug; $this->fieldLabel = $label; $this->valueKey = $valueKey; $this->types = $types; } public function label() { return $this->fieldLabel; } public function category() { return 'FluentCart'; } public function slug() { return $this->fieldSlug; } public function returnTypes() { return $this->types; } public function handler($attributes): StringData { $product = ProductContext::resolve(); $value = ''; if ($product) { switch ($this->valueKey) { case 'price': $value = FluentCartAdapter::formattedPrice($product); break; case 'sku': $value = FluentCartAdapter::sku($product); break; case 'compare_price': $value = FluentCartAdapter::formattedComparePrice($product); break; case 'stock': $value = FluentCartAdapter::stockLabel($product); break; case 'variation_id': $value = (string) FluentCartAdapter::variationId($product); break; case 'fulfillment': $value = FluentCartAdapter::fulfillmentType($product); break; case 'payment_type': $value = FluentCartAdapter::paymentType($product); break; case 'sale_state': $value = FluentCartAdapter::isAnyVariationOnSale($product) ? 'on-sale' : 'regular'; break; case 'id': $value = (string) FluentCartAdapter::id($product); break; case 'url': $value = (string) get_permalink(FluentCartAdapter::id($product)); break; case 'buy_now_url': $value = self::buyNowUrl($product); break; case 'add_to_cart_url': // See class docblock: no GET-based add-to-cart route exists, so this // resolves to the product permalink, not a fabricated URL scheme. $productId = FluentCartAdapter::id($product); $value = $productId ? (string) get_permalink($productId) : ''; break; case 'price_raw': $variation = ProductContext::defaultVariation($product); $value = $variation ? (string) (int) ($variation->item_price ?? 0) : ''; break; case 'currency': $value = class_exists('FluentCart\\Api\\CurrencySettings') ? (string) \FluentCart\Api\CurrencySettings::get('currency') : ''; break; case 'package_info': $value = self::packageInfo($product); break; case 'categories': $value = self::termList($product, TemplateRegistry::CATEGORY_TAXONOMY); break; case 'brands': $value = self::termList($product, TemplateRegistry::BRAND_TAXONOMY); break; case 'stock_quantity': $value = self::stockQuantity($product); break; } } return StringData::fromString($value); } /** @param object $product */ private static function buyNowUrl($product): string { $variation = ProductContext::defaultVariation($product); if (!$variation) { return ''; } if (method_exists($variation, 'getPurchaseUrl')) { return (string) $variation->getPurchaseUrl(); } $variationId = (int) ($variation->id ?? 0); if (!$variationId || !function_exists('site_url')) { return ''; } // Mirrors FluentCart\App\Models\ProductVariation::getPurchaseUrl()'s own literal // format exactly (app/Models/ProductVariation.php:298-300); used only if that real // method is ever unavailable. return site_url('?fluent-cart=instant_checkout&item_id=' . $variationId . '&quantity=1'); } /** @param object $product */ private static function packageInfo($product): string { $variation = ProductContext::defaultVariation($product); $otherInfo = $variation ? ($variation->other_info ?? null) : null; if (is_string($otherInfo)) { $decoded = json_decode($otherInfo, true); $otherInfo = is_array($decoded) ? $decoded : null; } if (!is_array($otherInfo) || !class_exists('FluentCart\\App\\Services\\Renderer\\ProductCardRender') || !method_exists('FluentCart\\App\\Services\\Renderer\\ProductCardRender', 'buildPackageInfoFromOtherInfo')) { return ''; } return (string) \FluentCart\App\Services\Renderer\ProductCardRender::buildPackageInfoFromOtherInfo($otherInfo); } /** @param object $product */ private static function termList($product, string $taxonomy): string { $productId = FluentCartAdapter::id($product); if (!$productId || !function_exists('get_the_term_list')) { return ''; } $list = get_the_term_list($productId, $taxonomy, '', ', '); if (!is_string($list) && !(function_exists('is_wp_error') && is_wp_error($list))) { return ''; } if (function_exists('is_wp_error') && is_wp_error($list)) { return ''; } return function_exists('wp_strip_all_tags') ? wp_strip_all_tags((string) $list) : strip_tags((string) $list); // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags -- Fallback only when WordPress is not loaded; the preferred branch uses wp_strip_all_tags(). } /** @param object $product */ private static function stockQuantity($product): string { $detail = $product->detail ?? null; if (!$detail || empty($detail->manage_stock)) { return ''; } $variation = ProductContext::defaultVariation($product); if (!$variation || !isset($variation->available)) { return ''; } return (string) (int) $variation->available; } }