<ø?php /** * SAL_TJE_Pricing_Data * * Lee y normaliza los campos ACF de precios/boletera para un evento. * * Regla dura: esta clase SOLO usa get_field()/get_sub_field()/have_rows(), * nunca the_field()/the_sub_field() (auto-escapan HTML desde ACF 6.2.7, * lo cual está bien para output directo pero rompe la idea de "datos * crudos, escaping centralizado en el Renderer"). * * @package SAL_TJE_Pricing */ defined('ABSPATH') or die(); class SAL_TJE_Pricing_Data { /** * Arreglo normalizado con todo lo que necesita el Renderer. * Punto de entrada único, evita consultar ACF dos veces. * * @return array{ * prices: array, * service_fees_enabled: bool, * box_office: array, * promoter: string * } */ public function get_pricing_data(int $post_id): array { if (!function_exists('get_field')) { return [ 'prices' => [], 'service_fees_enabled' => false, 'box_office' => $this->empty_box_office(), 'promoter' => '', ]; } return [ 'prices' => $this->get_prices($post_id), 'service_fees_enabled' => $this->get_service_fees_enabled($post_id), 'box_office' => $this->get_box_office($post_id), 'promoter' => $this->get_organizer_name($post_id), ]; } /** * Conveniencia para saber si hay algo que mostrar antes de llamar * get_pricing_data(). Si de todas formas vas a llamar get_pricing_data(), * revisa 'prices' ahí directo, para no consultar ACF dos veces. */ public function has_pricing_data(int $post_id): bool { return !empty($this->get_prices($post_id)); } /** * Filas del repeater "prices_repetear". */ private function get_prices(int $post_id): array { $rows = []; if (!function_exists('have_rows') || !have_rows('prices_repetear', $post_id)) { return $rows; } while (have_rows('prices_repetear', $post_id)) { the_row(); $rows[] = [ 'zone' => (string) get_sub_field('zone'), 'price' => (float) get_sub_field('price'), 'currency' => (string) get_sub_field('currency'), 'details' => (string) get_sub_field('details'), 'is_soldout' => (bool) get_sub_field('is_soldout'), ]; } return $rows; } /** * ¿Aplican cargos por servicio? (checkbox de una sola opción) */ private function get_service_fees_enabled(int $post_id): bool { $value = get_field('service_fees', $post_id); return !empty($value); } /** * Boletera: link online + UTM ya combinados, taquillas físicas, mapa. */ private function get_box_office(int $post_id): array { if (!function_exists('have_rows') || !have_rows('box_office_group', $post_id)) { return $this->empty_box_office(); } $link = ''; $utm_variables = ''; $raw_locations = ''; $seats_chart = ''; while (have_rows('box_office_group', $post_id)) { the_row(); $link = (string) get_sub_field('box_office_link'); $utm_variables = (string) get_sub_field('utm_variables'); $raw_locations = (string) get_sub_field('box_offices'); $seats_chart = (string) get_sub_field('seats_chart'); } return [ 'link' => $link ? esc_url_raw($this->build_ticket_url($link, $utm_variables)) : '', 'locations' => $this->parse_box_offices($raw_locations), 'seats_chart' => $seats_chart ? esc_url_raw($seats_chart) : '', ]; } /** * Combina el link de boletera con las variables UTM de forma segura, * sin duplicar "?" o "&" como hacía la concatenación manual original. */ private function build_ticket_url(string $link, string $utm_variables): string { if (!$utm_variables) { return $link; } $utm_params = []; wp_parse_str($utm_variables, $utm_params); if (empty($utm_params)) { return $link; } return add_query_arg($utm_params, $link); } /** * El textarea de taquillas es una lista libre, una por renglón. * Normaliza line endings, corta renglones vacíos. */ private function parse_box_offices(string $raw): array { if (!trim($raw)) { return []; } $normalized = str_replace("\r\n", "\n", $raw); $lines = explode("\n", $normalized); $locations = []; foreach ($lines as $line) { $line = trim($line); if ($line !== '') { $locations[] = $line; } } return $locations; } /** * Nombre del organizador (promotor) vía la taxonomía nativa de MEC. * Si un evento tiene más de un organizador, solo se toma el primero. */ private function get_organizer_name(int $post_id): string { $terms = get_the_terms($post_id, 'mec_organizer'); if (!is_array($terms) || empty($terms)) { return ''; } return (string) $terms[0]->name; } private function empty_box_office(): array { return [ 'link' => '', 'locations' => [], 'seats_chart' => '', ]; } } Class sal tje pricing hooks · PHP