d'] ?? '', 'mc_price_country_code' => $price_competitiveness['country_code'] ?? '', 'mc_product_currency_code' => $price_competitiveness['benchmark_price_currency_code'] ?? '', 'mc_product_price_micros' => $price_competitiveness['price_micros'] ?? '', 'mc_price_benchmark_price_micros' => $price_competitiveness['benchmark_price_micros'] ?? '', 'mc_price_benchmark_price_currency_code' => $price_competitiveness['benchmark_price_currency_code'] ?? '', 'mc_insights_suggested_price_micros' => $price_insights['suggested_price_micros'] ?? '', 'mc_insights_suggested_price_currency_code' => $price_insights['suggested_price_currency_code'] ?? '', 'mc_insights_predicted_impressions_change_fraction' => $price_insights['predicted_impressions_change_fraction'] ?? 0, 'mc_insights_predicted_clicks_change_fraction' => $price_insights['predicted_clicks_change_fraction'] ?? 0, 'mc_insights_predicted_conversions_change_fraction' => $price_insights['predicted_conversions_change_fraction'] ?? 0, 'mc_insights_effectiveness' => isset( $price_insights['effectiveness'] ) ? $this->get_effectiveness( $price_insights['effectiveness'] ) : 0, 'mc_metrics_clicks' => $performance['clicks'] ?? 0, 'mc_metrics_impressions' => $performance['impressions'] ?? 0, 'mc_metrics_ctr' => $performance['ctr'] ?? 0, 'mc_metrics_conversions' => $performance['conversions'] ?? 0, 'price_compared_with_benchmark' => $this->price_compared_with_benchmark( (int) $price_competitiveness['price_micros'], (int) $price_competitiveness['benchmark_price_micros'] ), ]; }, $mapped_data ); return $response_data; } /** * Retrieves the product thumbnail URL. * * @param int $product_id WooCommerce product ID. * @return string Product thumbnail URL or an empty string if not found. */ protected function get_product_thumbnail( int $product_id ): ?string { $thumbnail_id = get_post_thumbnail_id( $product_id ); if ( ! $thumbnail_id ) { return ''; } $thumbnail_url = wp_get_attachment_url( $thumbnail_id ); return $thumbnail_url ?? ''; } /** * Returns the key for the given effectiveness value. * * @param string $value Effectiveness value. * @return int The corresponding key if value is found, otherwise 0. */ public function get_effectiveness( $value ) { $effectiveness_map = [ 'EFFECTIVENESS_UNSPECIFIED' => 0, 'LOW' => 1, 'MEDIUM' => 2, 'HIGH' => 3, ]; return $effectiveness_map[ $value ] ?? 0; } /** * Update price benchmarks by querying the Google Content API and saving the data locally. */ public function update_price_benchmarks(): void { try { $benchmarks = $this->get_price_benchmarks_response( [] ); if ( empty( $benchmarks ) ) { return; } /** @var MerchantPriceBenchmarksQuery $query */ $query = $this->container->get( MerchantPriceBenchmarksQuery::class ); // Clear existing data before updating. $query->reload_data(); // Insert new benchmark data. foreach ( $benchmarks as $benchmark_item ) { $query->insert( $benchmark_item ); } } catch ( \Exception $e ) { do_action( 'woocommerce_gla_debug_message', $e->getMessage(), __METHOD__ ); } } /** * Compares a given price with a benchmark price. * * This function takes two prices in micros (1,000,000 micros = 1 unit of currency) * and performs a comparison to determine their relationship. * * @param int $price_micros The price to compare, in micros. * @param int $benchmark_price_micros The benchmark price to compare against, in micros. * @return bool Returns specific price compare group if the price meets the comparison criteria with the benchmark. */ private function price_compared_with_benchmark( $price_micros, $benchmark_price_micros ) { if ( empty( $price_micros ) || empty( $benchmark_price_micros ) ) { return 0; } elseif ( abs( $price_micros - $benchmark_price_micros ) <= ( $benchmark_price_micros * 0.01 ) ) { return 2; } elseif ( $price_micros < $benchmark_price_micros ) { return 1; } elseif ( $price_micros > $benchmark_price_micros ) { return 3; } } /** * Get a summary of price benchmarks. * * @return array */ public function get_summary(): array { /** @var MerchantPriceBenchmarksQuery $query */ $query = $this->container->get( MerchantPriceBenchmarksQuery::class ); // Get counts for all price comparison groups in one query. $benchmark_counts_result = $query->get_price_benchmark_counts(); // Convert raw DB results to an associative array with all groups. $benchmark_counts = $this->get_price_benchmark_counts_data( $benchmark_counts_result ); return [ 'total_products' => $benchmark_counts['total'] ?? 0, // Total products 'price_unknown' => $benchmark_counts[0] ?? 0, // Unknown/missing 'price_lower' => $benchmark_counts[1] ?? 0, // Lower price 'price_similar' => $benchmark_counts[2] ?? 0, // Similar price 'price_higher' => $benchmark_counts[3] ?? 0, // Higher price ]; } /** * Converts raw benchmark counts from the database to an associative array. * * @param array $rows Raw benchmark counts result from the database. * @return array Associative array with counts for each price comparison group and total. */ public function get_price_benchmark_counts_data( array $rows ): array { // Convert the results to a more usable format $counts = []; $total = 0; foreach ( $rows as $row ) { $price_compared_value = (int) $row['price_compared_with_benchmark']; $counts[ $price_compared_value ] = (int) $row['count']; $total += $counts[ $price_compared_value ]; } // Make sure all possible values are represented (0, 1, 2, 3) $all_values = [ 0, 1, 2, 3 ]; foreach ( $all_values as $value ) { if ( ! isset( $counts[ $value ] ) ) { $counts[ $value ] = 0; } } $counts['total'] = $total; return $counts; } /** * Retrieves formatted price benchmarks data from the local database. * * @param array $args { * Optional. Arguments to filter and paginate results. * * @type array|null $include List of product IDs to include. Default null. * @type int $page Offset for the results. Default 1. * @type int $per_page Maximum number of items returned. Default 10. * @type string $search Search string to filter results. Default null. * @type string $order Sort order: 'asc' or 'desc'. Default 'desc'. * @type string $orderby Attribute to sort by. Default 'mc_insights_effectiveness'. * } * @return array { * @type array $results List of formatted price benchmarks. * @type int $total Total number of price benchmarks available. * } */ public function get_price_benchmarks_data( array $args = [] ): array { $defaults = [ 'include' => null, 'page' => 1, 'per_page' => 10, 'search' => null, 'order' => 'desc', 'orderby' => self::DEFAULT_ORDERBY, ]; $args = wp_parse_args( array_intersect_key( $args, $defaults ), $defaults ); /** @var MerchantPriceBenchmarksQuery $query */ $query = $this->container->get( MerchantPriceBenchmarksQuery::class ); // Apply filters. if ( ! empty( $args['include'] ) && is_array( $args['include'] ) ) { $query->where( 'product_id', $args['include'], 'IN' ); } if ( ! empty( $args['search'] ) ) { $search = trim( $args['search'] ); $search_query = new \WP_Query( [ 'post_type' => [ 'product' ], 'post_status' => 'publish', 's' => $search, 'fields' => 'ids', 'posts_per_page' => -1, ] ); $product_ids = $search_query->posts; // If no products found, return empty results. if ( empty( $product_ids ) ) { return [ 'results' => [], 'total' => 0, ]; } $query->where( 'product_id', $product_ids, 'IN' ); } // Set order and orderby. $order = strtoupper( $args['order'] ); if ( ! in_array( $order, [ 'ASC', 'DESC' ], true ) ) { $order = 'DESC'; } $orderby = $this->map_orderby_to_db_value( $args['orderby'] ); $query->set_order( $orderby, $order ); // Set offset and limit. $query->set_offset( (int) ( $args['page'] - 1 ) * $args['per_page'] ); $query->set_limit( (int) $args['per_page'] ); // Get total count before limiting. $total = $query->get_count(); // Get results. $rows = $query->get_results(); // Format results. $results = []; foreach ( $rows as $row ) { $wc_product_id = (int) $row['product_id']; $product = wc_get_product( $wc_product_id ); $thumbnail = $this->get_product_thumbnail( $wc_product_id ); $results[] = [ 'product' => [ 'id' => $wc_product_id, 'thumbnail' => $thumbnail, 'title' => $product instanceof \WC_Product ? $product->get_name() : '', ], 'effectiveness' => (int) $row['mc_insights_effectiveness'] ?? 0, 'country_code' => $row['mc_price_country_code'] ?? '', 'currency_code' => $row['mc_product_currency_code'] ?? '', 'product_price' => $this->micros_to_float( (int) $row['mc_product_price_micros'] ), 'benchmark_price' => $this->micros_to_float( (int) $row['mc_price_benchmark_price_micros'] ), 'benchmark_price_currency_code' => $row['mc_price_benchmark_price_currency_code'] ?? '', 'price_gap' => $this->micros_to_float( (int) $row['mc_price_benchmark_price_micros'] - (int) $row['mc_product_price_micros'] ), 'suggested_price' => $this->micros_to_float( (int) $row['mc_insights_suggested_price_micros'] ), 'suggested_price_currency_code' => $row['mc_insights_suggested_price_currency_code'] ?? '', 'predicted_impressions_change' => $row['mc_insights_predicted_impressions_change_fraction'] ?? '', 'predicted_clicks_change' => $row['mc_insights_predicted_clicks_change_fraction'] ?? '', 'predicted_conversions_change' => $row['mc_insights_predicted_conversions_change_fraction'] ?? '', 'clicks' => (int) $row['mc_metrics_clicks'] ?? 0, 'impressions' => (int) $row['mc_metrics_impressions'] ?? 0, 'ctr' => $row['mc_metrics_ctr'] ?? 0, 'conversions' => (int) $row['mc_metrics_conversions'] ?? 0, 'price_compared_with_benchmark' => (int) $row['price_compared_with_benchmark'] ?? 0, ]; } return [ 'results' => $results, 'total' => $total, ]; } /** * Maps the orderby parameter to the corresponding database column name. * * @param string $order_by The orderby parameter from the request. * @return string The corresponding database column name. */ private function map_orderby_to_db_value( string $order_by ): string { // If the $order_by value is not in the COLUMN_MAP, use the default. if ( ! in_array( $order_by, array_keys( self::COLUMN_MAP ), true ) ) { $order_by = self::DEFAULT_ORDERBY; } return self::COLUMN_MAP[ $order_by ]; } /** * Converts a value in micros to a float representation. * * @param int $micros The value in micros (1,000,000 micros = 1 unit of currency). * @return float The converted float value. */ private function micros_to_float( int $micros ): float { // Convert micros to a float value. return round( $micros / 1000000, 2 ); } }
Warning: class_implements(): Class Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\PriceBenchmarks does not exist and could not be loaded in /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php on line 73

Warning: foreach() argument must be of type array|object, false given in /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php on line 73

Warning: Cannot modify header information - headers already sent by (output started at /htdocs/wp-content/plugins/google-listings-and-ads/src/MerchantCenter/PriceBenchmarks.php:1) in /htdocs/wp-content/plugins/the-events-calendar/src/Tribe/Views/V2/iCalendar/iCalendar_Handler.php on line 257

Warning: Cannot modify header information - headers already sent by (output started at /htdocs/wp-content/plugins/google-listings-and-ads/src/MerchantCenter/PriceBenchmarks.php:1) in /htdocs/wp-content/plugins/the-events-calendar/src/Tribe/iCal.php on line 511

Warning: Cannot modify header information - headers already sent by (output started at /htdocs/wp-content/plugins/google-listings-and-ads/src/MerchantCenter/PriceBenchmarks.php:1) in /htdocs/wp-content/plugins/the-events-calendar/src/Tribe/iCal.php on line 512

Warning: Cannot modify header information - headers already sent by (output started at /htdocs/wp-content/plugins/google-listings-and-ads/src/MerchantCenter/PriceBenchmarks.php:1) in /htdocs/wp-content/plugins/the-events-calendar/src/Tribe/iCal.php on line 513
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//The CandleLIT Experience - ECPv6.15.20//NONSGML v1.0//EN CALSCALE:GREGORIAN METHOD:PUBLISH X-ORIGINAL-URL:https://candlelitexperience.com X-WR-CALDESC:Events for The CandleLIT Experience REFRESH-INTERVAL;VALUE=DURATION:PT1H X-Robots-Tag:noindex X-PUBLISHED-TTL:PT1H BEGIN:VTIMEZONE TZID:Europe/Paris BEGIN:DAYLIGHT TZOFFSETFROM:+0100 TZOFFSETTO:+0200 TZNAME:CEST DTSTART:20250330T010000 END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:+0200 TZOFFSETTO:+0100 TZNAME:CET DTSTART:20251026T010000 END:STANDARD BEGIN:DAYLIGHT TZOFFSETFROM:+0100 TZOFFSETTO:+0200 TZNAME:CEST DTSTART:20260329T010000 END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:+0200 TZOFFSETTO:+0100 TZNAME:CET DTSTART:20261025T010000 END:STANDARD BEGIN:DAYLIGHT TZOFFSETFROM:+0100 TZOFFSETTO:+0200 TZNAME:CEST DTSTART:20270328T010000 END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:+0200 TZOFFSETTO:+0100 TZNAME:CET DTSTART:20271031T010000 END:STANDARD END:VTIMEZONE BEGIN:VTIMEZONE TZID:America/Chicago BEGIN:DAYLIGHT TZOFFSETFROM:-0600 TZOFFSETTO:-0500 TZNAME:CDT DTSTART:20250309T080000 END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:-0500 TZOFFSETTO:-0600 TZNAME:CST DTSTART:20251102T070000 END:STANDARD BEGIN:DAYLIGHT TZOFFSETFROM:-0600 TZOFFSETTO:-0500 TZNAME:CDT DTSTART:20260308T080000 END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:-0500 TZOFFSETTO:-0600 TZNAME:CST DTSTART:20261101T070000 END:STANDARD BEGIN:DAYLIGHT TZOFFSETFROM:-0600 TZOFFSETTO:-0500 TZNAME:CDT DTSTART:20270314T080000 END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:-0500 TZOFFSETTO:-0600 TZNAME:CST DTSTART:20271107T070000 END:STANDARD END:VTIMEZONE BEGIN:VEVENT DTSTART;TZID=Europe/Paris:20260228T120000 DTEND;TZID=Europe/Paris:20260228T145900 DTSTAMP:20260413T083953 CREATED:20251005T200110Z LAST-MODIFIED:20260128T224251Z UID:9452-1772280000-1772290740@candlelitexperience.com SUMMARY:Plant & Pour: Candle Making + Plant Terrarium Workshop DESCRIPTION:Join us for a fun Plant & Pour Workshop where you can create your own plant terrarium and hand-pour a candle to take home!\nRSVP Here\n\n\n\nWelcome to the Plant & Pour Workshop at Energy Gardens Terrariums! Join us for a fun-filled event where you can craft your very own plant terrarium and hand-pour a unique creation. Get your hands dirty while learning about plant care and design. This in-person workshop is perfect for plant lovers and craft enthusiasts alike. Don’t miss out on this opportunity to unleash your creativity and take home a beautiful piece of greenery + fill your home with the aromas of your new candle creation! \nWhen: Saturday\, January 31 at 12pm and Saturday\, February 28\, 2026 (pick one or pick both!) \n\nCandle Making begins at 12:30pm\nPlant Terrarium instruction begins at 1:30 pm\nAny remaining time will be for mingling!\n\nParking: Free street parking available \nCheck out our last Plant & Pour: https://www.instagram.com/reel/DQmo6Y-EUAj/?igsh=Z3c0aGl4N2dncGds \nTickets are non-refundable. If you are no loger able to attend in person please email Info@CandlelitExperience.com and an at home candle making kit will be shipped to you URL:https://candlelitexperience.com/event/plant-pour/ CATEGORIES:Workshops ATTACH;FMTTYPE=image/jpeg:https://candlelitexperience.com/wp-content/uploads/2025/09/IMG_1005-scaled.jpg END:VEVENT BEGIN:VEVENT DTSTART;TZID=America/Chicago:20260404T130000 DTEND;TZID=America/Chicago:20260404T150000 DTSTAMP:20260413T083953 CREATED:20260324T004022Z LAST-MODIFIED:20260402T201904Z UID:10183-1775307600-1775314800@candlelitexperience.com SUMMARY:Spring Fling Dallas at SNAP Bakeshop DESCRIPTION:Apr 12\, 2026\, 1:00 PM – 4:00 PM \nThe Bakeshop\, 1430 Dragon St Unit 1 Building 2\, Dallas\, TX 75207\, USA \n\n\nAbout the event\n\n\n\n\nWe’re welcoming the season in the sweetest way possible with a collaborative experience between SNAP Bakeshop and Candlelit Experience. \nGuests will start by decorating their own floral-themed bento cake + cupcake box combo — think soft spring colors\, textured florals\, and all the pretty details. Then\, we’ll transition into a guided candle-making session where you’ll blend floral-inspired scents to create a custom candle that feels like spring in a jar. \nEnjoy light bites\, refreshing drinks\, interactive games\, and a few mystery prizes throughout the evening. It’s creativity\, community\, and curated vibes — all in one beautiful spring experience. \nCome ready to decorate\, pour\, and bloom with us. 🌷 \nTickets: https://www.eventbrite.com/e/spring-fling-luxe-diy-experience-cake-candle-decorating-tickets-1985821852618 \n\n\n\n\nNeed more info? Leave an inquiry below.\n\n\nGo back Your message has been sent\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\nName(required)\n\n \n \n \n \n \n \n \n \n Warning\n \n \n \n \n\n\nEmail(required)\n\n \n \n \n \n \n \n \n \n Warning\n \n \n \n \n\n\nWebsite\n\n \n \n \n \n \n \n \n \n Warning\n \n \n \n \n\n\nMessage\n\n \n \n \n \n \n \n \n \n Warning\n \n \n \n \n \nWarning.\n \n \n \n \n \n Submit URL:https://candlelitexperience.com/event/spring-fling-dallas-at-snap-bakeshop/ LOCATION:SNAP Bakeshop\, 1430 Dragon St Unit 1 Building 2\,\, Dallas\, Texas\, 75207\, United States ATTACH;FMTTYPE=image/png:https://candlelitexperience.com/wp-content/uploads/2026/03/Screen-Shot-2026-03-23-at-7.38.54-PM.png ORGANIZER;CN="Candlelit Experience":MAILTO:CampusCandlesco@gmail.com END:VEVENT BEGIN:VEVENT DTSTART;VALUE=DATE:20260510 DTEND;VALUE=DATE:20260511 DTSTAMP:20260413T083953 CREATED:20251007T004129Z LAST-MODIFIED:20260324T004057Z UID:9553-1778371200-1778457599@candlelitexperience.com SUMMARY:Hugs & Love: 3rd Annual Mothers Day Brunch DESCRIPTION:Join The Creative Juices Group and The Candlelit Experience May 9th to enjoy a hands on candle-making experience\n\n\n\nThe Creative Juices Group® & The Candlelit Experience Presents: 3rd Annual Hugs & Love | A Mother’s Day Brunch & Candle-Making Experience \nBring your mother\, wife\, sister\, aunt or friend! and come have fun with us as we make this Mother’s Day a special one yet again! Enjoy Brunch vibes + a Hands-on candle-making class led by The Candlelit Experience. In addition to Music\, Mimosa bar\, Catered Brunch and DIY Flower Bouquet Bar. \nPLEASE NOTE THIS IS AN INTIMATE STYLE EVENT & SEATS ARE VERY LIMITED!!… THIS IS AN ADULT EVENT 21+ \nSaturday May 9\, 2025 | 12:00PM – 3:00PM (Brunch) \nLocation: Dallas Texas\, 75215 \nTICKET INCLUDES: \n\nHands on CANDLE-MAKING CLASS led by The Candlelit Experience\nMeet Founder/CEO of The Creative Juices Group & The Creative Juices Group – Studio\nCreate your own 8oz Candle from choice of Candle color\, Vessel and Fragrance\nFlower Bar ( you may add flowers to your candle or leave as is once made)\n**Remeberance Candle Option Available: In honor of those who’ve lost their mothers or mother figures**\nMimosa Bar or Signature Cocktail\nMusic| Vibes | Fun\nCatered Brunch options (Includes 1 appetizer\, 1 main course\, and Dessert)\nAdditional Refreshments\nAccess to take selfies on event backdrop\nFree parking\n\nPLEASE NOTE: SEATS ARE LIMITED AND THIS EVENT IS NON-REFUNDABLE!! – ALL SALES ARE FINAL URL:https://candlelitexperience.com/event/hugs-love-3rd-annual-mothers-day-brunch/ LOCATION:Dallas\, Texas\, 500 Singleton blvdunit 1109\, Dallas\, TX\, 75212\, United States CATEGORIES:Workshops ATTACH;FMTTYPE=image/png:https://candlelitexperience.com/wp-content/uploads/2025/10/Screen-Shot-2026-01-28-at-4.14.08-PM.png END:VEVENT END:VCALENDAR