'In welchem Monat startet traditionell der Advent?', 'options' => array( 'Oktober', 'November', 'Dezember', 'Januar' ), 'correct' => 2, ), array( 'q' => 'Wie viele Türchen hat ein klassischer Adventskalender?', 'options' => array( '12', '24', '25', '31' ), 'correct' => 1, ), array( 'q' => 'Welches Gewürz darf in Lebkuchen nicht fehlen?', 'options' => array( 'Kurkuma', 'Zimt', 'Paprika', 'Kreuzkümmel' ), 'correct' => 1, ), array( 'q' => 'Welche Farbe wird am häufigsten mit Weihnachten verbunden?', 'options' => array( 'Türkis', 'Rot', 'Lila', 'Grau' ), 'correct' => 1, ), ); } /** * The 24 sponsor/prize/quiz records (without day index or filler question). * * @return array */ public static function raw_doors() { return array( array( 'sponsor' => 'Rösterei Nordlicht', 'sponsorText' => 'Handgeröstete Spezialitätenkaffees aus fair gehandelten Bohnen — seit 2008 mitten in der Altstadt.', 'prize' => 'Kaffee-Genuss-Paket', 'prizeText' => 'Drei sortenreine Röstungen (750 g), eine handgefertigte Keramiktasse und ein Filter-Starterset.', 'value' => 'ca. 75 €', 'q' => array( 'q' => 'Womit handelt die Rösterei Nordlicht?', 'options' => array( 'Tee', 'Spezialitätenkaffee', 'Schokolade', 'Wein' ), 'correct' => 1 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Buchhandlung Seitenwind', 'sponsorText' => 'Die unabhängige Buchhandlung mit kuratierter Auswahl, Lesungen und einer gemütlichen Leseecke.', 'prize' => 'Büchergutschein über 100 €', 'prizeText' => 'Einlösbar auf das gesamte Sortiment — von Bestsellern bis zu seltenen Bildbänden.', 'value' => '100 €', 'q' => array( 'q' => 'Was bietet die Buchhandlung Seitenwind regelmäßig an?', 'options' => array( 'Konzerte', 'Lesungen', 'Kochkurse', 'Yoga' ), 'correct' => 1 ), 'social' => array( 'instagram', 'newsletter' ), ), array( 'sponsor' => 'Wellness-Oase Aurelia', 'sponsorText' => 'Ein Rückzugsort mit Sauna-Landschaft, Massagen und Ruheräumen mitten in der Stadt.', 'prize' => 'Spa-Tag für zwei Personen', 'prizeText' => 'Ganztägiger Zugang zur Sauna-Welt inklusive zweier 50-minütiger Aroma-Massagen.', 'value' => 'ca. 180 €', 'q' => array( 'q' => 'Was gehört zum Angebot der Wellness-Oase Aurelia?', 'options' => array( 'Sauna & Massagen', 'Autowäsche', 'Steuerberatung', 'Fahrradverleih' ), 'correct' => 0 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Genussmanufaktur Tannhof', 'sponsorText' => 'Regionale Feinkost aus eigener Herstellung: Aufstriche, Chutneys und Öle ohne Zusatzstoffe.', 'prize' => 'Großer Feinkostkorb', 'prizeText' => 'Eine Auswahl aus zwölf hauseigenen Spezialitäten, liebevoll in Holzwolle verpackt.', 'value' => 'ca. 90 €', 'q' => array( 'q' => 'Wie stellt die Genussmanufaktur Tannhof ihre Produkte her?', 'options' => array( 'Industriell', 'In eigener Herstellung', 'Import', 'Tiefkühl' ), 'correct' => 1 ), 'social' => array( 'instagram', 'newsletter' ), ), array( 'sponsor' => 'Fahrradwerkstatt Pedalo', 'sponsorText' => 'Meisterbetrieb für Reparatur, Wartung und Beratung rund ums Rad — auch für E-Bikes.', 'prize' => 'E-Bike-Service-Paket', 'prizeText' => 'Komplett-Check, Bremsen- und Schaltungseinstellung sowie eine Akku-Diagnose.', 'value' => 'ca. 120 €', 'q' => array( 'q' => 'Worauf ist die Fahrradwerkstatt Pedalo spezialisiert?', 'options' => array( 'Autos', 'Fahrräder & E-Bikes', 'Motorräder', 'Boote' ), 'correct' => 1 ), 'social' => array( 'facebook' ), ), array( 'sponsor' => 'Teehaus Yuzu', 'sponsorText' => 'Über 120 lose Tees aus aller Welt, dazu Zubehör und kleine Verkostungen am Wochenende.', 'prize' => 'Großes Tee-Probierset', 'prizeText' => 'Acht handverlesene Sorten in wiederverwendbaren Dosen plus ein Glas-Teebereiter.', 'value' => 'ca. 60 €', 'q' => array( 'q' => 'Was kann man im Teehaus Yuzu am Wochenende erleben?', 'options' => array( 'Verkostungen', 'Kinoabende', 'Flohmarkt', 'Tanzkurse' ), 'correct' => 0 ), 'social' => array( 'instagram', 'tiktok' ), ), array( 'sponsor' => 'Schokoladerie Cacao Vera', 'sponsorText' => 'Bean-to-Bar-Manufaktur mit eigener Conchierung — vom Edelkakao bis zur fertigen Praline.', 'prize' => 'Pralinen-Adventsbox', 'prizeText' => '24 von Hand gefüllte Pralinen in einer edlen Geschenkbox mit Goldprägung.', 'value' => 'ca. 45 €', 'q' => array( 'q' => 'Was bedeutet „Bean-to-Bar“?', 'options' => array( 'Vom Restaurant zur Bar', 'Von der Bohne zur Tafel', 'Eine Tanzform', 'Ein Cocktail' ), 'correct' => 1 ), 'social' => array( 'instagram', 'facebook', 'tiktok' ), ), array( 'sponsor' => 'Fotostudio Lichtblick', 'sponsorText' => 'Porträt-, Familien- und Businessfotografie mit natürlichem Licht und entspannter Atmosphäre.', 'prize' => 'Familien-Fotoshooting', 'prizeText' => 'Einstündiges Shooting inklusive Bildauswahl und zehn bearbeiteter Digitalbilder.', 'value' => 'ca. 150 €', 'q' => array( 'q' => 'Worauf legt das Fotostudio Lichtblick besonderen Wert?', 'options' => array( 'Blitzgewitter', 'Natürliches Licht', 'Schwarz-Weiß nur', 'Drohnen' ), 'correct' => 1 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Restaurant Zum Goldenen Hirsch', 'sponsorText' => 'Saisonale Küche mit regionalen Zutaten in historischem Ambiente seit drei Generationen.', 'prize' => 'Dinner für zwei Personen', 'prizeText' => 'Viergänge-Überraschungsmenü des Küchenchefs inklusive korrespondierender Getränke.', 'value' => 'ca. 160 €', 'q' => array( 'q' => 'Welche Küche bietet der Goldene Hirsch?', 'options' => array( 'Fast Food', 'Saisonal & regional', 'Nur Desserts', 'Frittiertes' ), 'correct' => 1 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Sportstudio Vital', 'sponsorText' => 'Modernes Trainingszentrum mit Kursen, Gerätepark und persönlicher Trainingsbetreuung.', 'prize' => '3-Monats-Mitgliedschaft', 'prizeText' => 'Voller Zugang zu allen Kursen und Geräten plus ein Personal-Training zum Start.', 'value' => 'ca. 200 €', 'q' => array( 'q' => 'Was bietet das Sportstudio Vital zum Einstieg?', 'options' => array( 'Eine Pizza', 'Ein Personal-Training', 'Ein Buch', 'Einen Kaffee' ), 'correct' => 1 ), 'social' => array( 'instagram', 'tiktok' ), ), array( 'sponsor' => 'Weingut Sonnenhang', 'sponsorText' => 'Familiengeführtes Weingut in Steillage mit naturnahem Anbau und prämierten Tropfen.', 'prize' => 'Wein-Selektion', 'prizeText' => 'Sechs Flaschen aus dem aktuellen Jahrgang, kuratiert vom Winzer persönlich.', 'value' => 'ca. 95 €', 'q' => array( 'q' => 'In welcher Lage wächst der Wein vom Sonnenhang?', 'options' => array( 'Steillage', 'Im Gewächshaus', 'Am Strand', 'Im Keller' ), 'correct' => 0 ), 'social' => array( 'instagram', 'newsletter' ), ), array( 'sponsor' => 'Spielwaren Kunterbunt', 'sponsorText' => 'Liebevoll sortiertes Spielwarengeschäft mit nachhaltigem Holzspielzeug und Gesellschaftsspielen.', 'prize' => 'Spielzeug-Gutschein über 80 €', 'prizeText' => 'Frei einlösbar — von Holzeisenbahnen bis zum Familien-Brettspiel des Jahres.', 'value' => '80 €', 'q' => array( 'q' => 'Worauf setzt Spielwaren Kunterbunt besonders?', 'options' => array( 'Plastikfiguren', 'Nachhaltiges Holzspielzeug', 'Elektronik', 'Kleidung' ), 'correct' => 1 ), 'social' => array( 'instagram', 'facebook', 'youtube' ), ), array( 'sponsor' => 'Floristik Blütenzauber', 'sponsorText' => 'Florales Handwerk für jeden Anlass — von der Tischdeko bis zum Brautstrauß.', 'prize' => 'Blumenabo für 3 Monate', 'prizeText' => 'Jede Woche ein frischer, saisonaler Strauß, direkt nach Hause geliefert.', 'value' => 'ca. 120 €', 'q' => array( 'q' => 'Was gestaltet Floristik Blütenzauber unter anderem?', 'options' => array( 'Brautsträuße', 'Computer', 'Schuhe', 'Möbel' ), 'correct' => 0 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Kosmetik Reinhaut', 'sponsorText' => 'Naturkosmetik-Studio mit Hautanalyse, Behandlungen und veganen Pflegeprodukten.', 'prize' => 'Pflege-Set', 'prizeText' => 'Reinigung, Serum und Feuchtigkeitscreme aus der hauseigenen Naturkosmetik-Linie.', 'value' => 'ca. 85 €', 'q' => array( 'q' => 'Welche Produkte bietet Kosmetik Reinhaut?', 'options' => array( 'Vegane Naturkosmetik', 'Autoteile', 'Tierfutter', 'Werkzeug' ), 'correct' => 0 ), 'social' => array( 'instagram', 'tiktok' ), ), array( 'sponsor' => 'Möbelhaus Wohnglück', 'sponsorText' => 'Einrichtungshaus mit Fokus auf langlebige Möbel, Wohnberatung und stilvolle Deko.', 'prize' => 'Deko-Gutschein über 100 €', 'prizeText' => 'Für alles aus der Wohnaccessoire-Abteilung — Kissen, Leuchten, Vasen und mehr.', 'value' => '100 €', 'q' => array( 'q' => 'Worauf legt Möbelhaus Wohnglück Wert?', 'options' => array( 'Wegwerfmöbel', 'Langlebige Möbel', 'Gebrauchtwagen', 'Lebensmittel' ), 'correct' => 1 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Brauerei Hopfengold', 'sponsorText' => 'Handwerksbrauerei mit Craft-Bieren nach dem Reinheitsgebot und offener Schaubrauerei.', 'prize' => 'Bier-Tasting für 4 Personen', 'prizeText' => 'Geführte Verkostung von sechs Spezialitäten inklusive Brauereiführung.', 'value' => 'ca. 110 €', 'q' => array( 'q' => 'Nach welchem Gebot braut Hopfengold?', 'options' => array( 'Reinheitsgebot', 'Schweigegebot', 'Tempolimit', 'Gebot der Stunde' ), 'correct' => 0 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Optik Klarblick', 'sponsorText' => 'Augenoptik mit moderner Sehanalyse, individueller Beratung und ausgewählten Fassungen.', 'prize' => 'Designer-Sonnenbrille', 'prizeText' => 'Eine Fassung nach Wahl aus der aktuellen Kollektion inklusive UV-Schutzgläsern.', 'value' => 'ca. 130 €', 'q' => array( 'q' => 'Was bietet Optik Klarblick an?', 'options' => array( 'Sehanalyse & Fassungen', 'Pizza', 'Reparatur von Uhren', 'Tauchkurse' ), 'correct' => 0 ), 'social' => array( 'instagram' ), ), array( 'sponsor' => 'Bäckerei Korn & Co', 'sponsorText' => 'Traditionsbäckerei mit langer Teigführung, Natursauerteig und täglich frischem Brot.', 'prize' => 'Brot-Abo für einen Monat', 'prizeText' => 'Jede Woche ein frisches Sauerteigbrot deiner Wahl zum Abholen in der Filiale.', 'value' => 'ca. 50 €', 'q' => array( 'q' => 'Womit arbeitet die Bäckerei Korn & Co?', 'options' => array( 'Backmischung', 'Natursauerteig', 'Fertigteig', 'Mikrowelle' ), 'correct' => 1 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Reisebüro Fernweh', 'sponsorText' => 'Persönliche Reiseberatung mit Herzblut — von der Städtereise bis zur Fernreise.', 'prize' => 'Wochenend-Reise-Gutschein', 'prizeText' => 'Gutschein über 250 € für eine Kurzreise nach Wahl aus dem Partnerkatalog.', 'value' => '250 €', 'q' => array( 'q' => 'Worauf ist das Reisebüro Fernweh spezialisiert?', 'options' => array( 'Reiseberatung', 'Autoreparatur', 'Möbel', 'Versicherungen' ), 'correct' => 0 ), 'social' => array( 'instagram', 'facebook', 'newsletter' ), ), array( 'sponsor' => 'Musikhaus Klangwelt', 'sponsorText' => 'Instrumente, Zubehör und HiFi — mit fachkundiger Beratung und eigener Werkstatt.', 'prize' => 'Bluetooth-Kopfhörer', 'prizeText' => 'Kabelloser Over-Ear-Kopfhörer mit aktiver Geräuschunterdrückung und langer Akkulaufzeit.', 'value' => 'ca. 180 €', 'q' => array( 'q' => 'Was findet man im Musikhaus Klangwelt?', 'options' => array( 'Instrumente & HiFi', 'Gartenmöbel', 'Lebensmittel', 'Kleidung' ), 'correct' => 0 ), 'social' => array( 'instagram', 'youtube', 'tiktok' ), ), array( 'sponsor' => 'Gärtnerei Grünzeug', 'sponsorText' => 'Stadtgärtnerei mit Zimmerpflanzen, Kräutern und torffreier, nachhaltiger Erde.', 'prize' => 'Pflanzen-Set', 'prizeText' => 'Drei pflegeleichte Zimmerpflanzen in handgetöpferten Übertöpfen plus Pflege-Set.', 'value' => 'ca. 70 €', 'q' => array( 'q' => 'Welche Erde verwendet die Gärtnerei Grünzeug?', 'options' => array( 'Torffreie Erde', 'Beton', 'Sand vom Strand', 'Styropor' ), 'correct' => 0 ), 'social' => array( 'instagram', 'tiktok' ), ), array( 'sponsor' => 'Käserei Almgenuss', 'sponsorText' => 'Handwerkskäserei mit Bergmilch von Weidetieren und langgereiften Spezialitäten.', 'prize' => 'Große Käse-Platte', 'prizeText' => 'Sieben gereifte Käsesorten mit Chutney, Nüssen und hausgemachtem Früchtebrot.', 'value' => 'ca. 80 €', 'q' => array( 'q' => 'Woher stammt die Milch der Käserei Almgenuss?', 'options' => array( 'Von Weidetieren', 'Aus dem Labor', 'Aus Pulver', 'Unbekannt' ), 'correct' => 0 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Juwelier Sternenglanz', 'sponsorText' => 'Meisteratelier für Schmuck und Uhren — mit eigener Goldschmiede und Anfertigung nach Wunsch.', 'prize' => 'Schmuck-Gutschein über 200 €', 'prizeText' => 'Einlösbar auf das gesamte Sortiment oder eine individuelle Anfertigung.', 'value' => '200 €', 'q' => array( 'q' => 'Was hat Juwelier Sternenglanz im Haus?', 'options' => array( 'Eine Goldschmiede', 'Eine Bäckerei', 'Ein Schwimmbad', 'Eine Tankstelle' ), 'correct' => 0 ), 'social' => array( 'instagram', 'facebook' ), ), array( 'sponsor' => 'Hotel Bergkristall', 'sponsorText' => 'Vier-Sterne-Wohlfühlhotel in den Bergen mit Panorama-Spa, Gourmetküche und Bergblick.', 'prize' => 'Hauptpreis: 2 Übernachtungen für 2 Personen', 'prizeText' => 'Zwei Nächte im Doppelzimmer mit Halbpension, Spa-Zugang und Begrüßungsüberraschung.', 'value' => 'ca. 600 €', 'q' => array( 'q' => 'Was bietet das Hotel Bergkristall seinen Gästen?', 'options' => array( 'Panorama-Spa', 'Go-Kart-Bahn', 'Kegelbahn', 'Autokino' ), 'correct' => 0 ), 'social' => array( 'instagram', 'facebook', 'youtube', 'newsletter' ), ), ); } /** * Full default dataset with day index and the 2-question quiz assembled * exactly like the prototype (sponsor question + cycled festive question). * * @return array */ /** * Configured number of doors/items (1..31, default 24). * * @return int */ public static function door_count() { $opts = ADVK_Settings::get_options(); $count = isset( $opts['door_count'] ) ? (int) $opts['door_count'] : 24; return max( 1, min( 31, $count ) ); } public static function default_calendar() { $raw = self::raw_doors(); $festive = self::festive_questions(); $calendar = array(); $count = self::door_count(); $rawN = count( $raw ); for ( $i = 0; $i < $count; $i++ ) { $d = $raw[ $i % $rawN ]; // cycle the built-in content if count > built-ins $prizes = array( array( 'title' => $d['prize'], 'text' => $d['prizeText'], 'value' => $d['value'], 'qty' => 1, 'image' => '', ), ); $calendar[] = array( 'day' => $i + 1, 'sponsor' => $d['sponsor'], 'sponsorText' => $d['sponsorText'], 'sponsorUrl' => '', 'prize' => $d['prize'], 'prizeText' => $d['prizeText'], 'value' => $d['value'], 'prizes' => $prizes, 'winnerCount' => 1, 'logo' => '', 'prizeImage' => '', 'image' => '', 'donateUrl' => '', 'donateText' => '', 'social' => $d['social'], 'socialUrls' => array(), 'quiz' => array( $d['q'], $festive[ $i % count( $festive ) ] ), ); } return $calendar; } /** * Allowed social channel keys. * * @return array */ public static function social_keys() { return array( 'instagram', 'facebook', 'tiktok', 'youtube', 'linkedin', 'newsletter' ); } /** * Determine the active "today" day (1..24). * * Admin may override; otherwise it derives from the current date in * December. Outside December (with no override) it returns 0 (none open). * * @return int */ public static function today_day() { $opts = ADVK_Settings::get_options(); $count = self::door_count(); $override = isset( $opts['today_override'] ) ? (int) $opts['today_override'] : 0; if ( $override >= 1 && $override <= $count ) { return $override; } $mode = isset( $opts['reveal_mode'] ) ? (string) $opts['reveal_mode'] : 'advent'; $now = current_time( 'timestamp' ); if ( 'startdate' === $mode ) { // One item unlocks per day from the configured start date. $start = isset( $opts['start_date'] ) ? (string) $opts['start_date'] : ''; if ( '' === $start ) { return 0; } $start_ts = strtotime( $start . ' 00:00:00' ); $today_ts = strtotime( wp_date( 'Y-m-d', $now ) . ' 00:00:00' ); if ( ! $start_ts || $today_ts < $start_ts ) { return 0; } $days = (int) floor( ( $today_ts - $start_ts ) / DAY_IN_SECONDS ) + 1; return max( 0, min( $count, $days ) ); } // Advent mode: derive from the December date. $month = (int) wp_date( 'n', $now ); $day = (int) wp_date( 'j', $now ); if ( 12 === $month && $day >= 1 ) { return min( $count, $day ); } return 0; } /** * Read the live calendar: published door CPT posts merged over the * defaults, indexed by day. Falls back entirely to defaults if none exist. * * @return array Ordered list of door arrays (day 1..24). */ public static function get_calendar() { $defaults = self::default_calendar(); $by_day = array(); foreach ( $defaults as $d ) { $by_day[ $d['day'] ] = $d; } $count = self::door_count(); $posts = get_posts( array( 'post_type' => ADVK_Doors_CPT::POST_TYPE, 'post_status' => 'publish', 'numberposts' => 31, 'meta_key' => '_advk_day', 'orderby' => 'meta_value_num', 'order' => 'ASC', ) ); foreach ( $posts as $post ) { $day = (int) get_post_meta( $post->ID, '_advk_day', true ); if ( $day < 1 || $day > $count ) { continue; } $by_day[ $day ] = self::door_from_post( $post, $day ); } // Only expose exactly the configured number of days (1..count). foreach ( array_keys( $by_day ) as $d ) { if ( $d < 1 || $d > $count ) { unset( $by_day[ $d ] ); } } ksort( $by_day ); return array_values( $by_day ); } /** * Build a door array from a CPT post + its meta. * * @param WP_Post $post Door post. * @param int $day Day number. * @return array */ public static function door_from_post( $post, $day ) { $quiz = get_post_meta( $post->ID, '_advk_quiz', true ); if ( ! is_array( $quiz ) || empty( $quiz ) ) { $quiz = array(); } $social = get_post_meta( $post->ID, '_advk_social', true ); if ( ! is_array( $social ) ) { $social = array(); } $social_urls = get_post_meta( $post->ID, '_advk_social_urls', true ); if ( ! is_array( $social_urls ) ) { $social_urls = array(); } $logo_id = (int) get_post_meta( $post->ID, '_advk_logo_id', true ); $prize_id = (int) get_post_meta( $post->ID, '_advk_prize_image_id', true ); $door_id = (int) get_post_meta( $post->ID, '_advk_door_image_id', true ); $legacy_prize = (string) get_post_meta( $post->ID, '_advk_prize', true ); $legacy_text = (string) get_post_meta( $post->ID, '_advk_prize_text', true ); $legacy_value = (string) get_post_meta( $post->ID, '_advk_value', true ); $prizes = self::normalize_prizes( get_post_meta( $post->ID, '_advk_prizes', true ), array( 'title' => $legacy_prize, 'text' => $legacy_text, 'value' => $legacy_value, 'image_id' => $prize_id, ) ); // Number of winners = total prize quantity (sum of each prize's "Anzahl"). // Backward compatible: if no per-prize quantities are used (all 1) but a // legacy "Anzahl Gewinner" was set higher, honour that instead. $sum_qty = 0; foreach ( $prizes as $p ) { $sum_qty += isset( $p['qty'] ) ? max( 1, (int) $p['qty'] ) : 1; } $n_prizes = count( $prizes ); $stored_wc = (int) get_post_meta( $post->ID, '_advk_winner_count', true ); if ( $sum_qty > $n_prizes ) { $winner_count = $sum_qty; } elseif ( $stored_wc > $n_prizes ) { $winner_count = $stored_wc; } else { $winner_count = max( 1, $n_prizes ); } $first = isset( $prizes[0] ) ? $prizes[0] : array( 'title' => '', 'text' => '', 'value' => '', 'image' => '' ); return array( 'day' => $day, 'sponsor' => get_the_title( $post ), 'sponsorText' => (string) get_post_meta( $post->ID, '_advk_sponsor_text', true ), 'sponsorUrl' => (string) get_post_meta( $post->ID, '_advk_sponsor_url', true ), 'prize' => $first['title'], 'prizeText' => $first['text'], 'value' => $first['value'], 'prizes' => $prizes, 'winnerCount' => $winner_count, 'logo' => $logo_id ? (string) wp_get_attachment_image_url( $logo_id, 'medium' ) : '', 'prizeImage' => $first['image'], 'image' => $door_id ? (string) wp_get_attachment_image_url( $door_id, 'medium' ) : '', 'donateUrl' => (string) get_post_meta( $post->ID, '_advk_donate_url', true ), 'donateText' => (string) get_post_meta( $post->ID, '_advk_donate_text', true ), 'social' => array_values( array_intersect( $social, self::social_keys() ) ), 'socialUrls' => $social_urls, 'quiz' => $quiz, ); } /** * Normalise stored prize rows into a clean list of * { title, text, value, image } (image resolved to a URL). Falls back to a * single legacy prize (from the old single-prize meta) when no list exists, * so doors created before multi-prize support keep working unchanged. * * @param mixed $stored Raw `_advk_prizes` meta (array of rows) or empty. * @param array $legacy Legacy single-prize fallback (title/text/value/image_id). * @return array List of prize dicts (always at least one entry). */ public static function normalize_prizes( $stored, $legacy = array() ) { $out = array(); if ( is_array( $stored ) ) { foreach ( $stored as $row ) { if ( ! is_array( $row ) ) { continue; } $title = isset( $row['title'] ) ? (string) $row['title'] : ''; $text = isset( $row['text'] ) ? (string) $row['text'] : ''; $value = isset( $row['value'] ) ? (string) $row['value'] : ''; $img = isset( $row['image_id'] ) ? (int) $row['image_id'] : 0; $qty = isset( $row['qty'] ) ? max( 1, (int) $row['qty'] ) : 1; // Skip fully empty rows. if ( '' === $title && '' === $text && '' === $value && ! $img ) { continue; } $out[] = array( 'title' => $title, 'text' => $text, 'value' => $value, 'qty' => $qty, 'image' => $img ? (string) wp_get_attachment_image_url( $img, 'large' ) : '', ); } } if ( empty( $out ) ) { $img = isset( $legacy['image_id'] ) ? (int) $legacy['image_id'] : 0; $out[] = array( 'title' => isset( $legacy['title'] ) ? (string) $legacy['title'] : '', 'text' => isset( $legacy['text'] ) ? (string) $legacy['text'] : '', 'value' => isset( $legacy['value'] ) ? (string) $legacy['value'] : '', 'qty' => 1, 'image' => $img ? (string) wp_get_attachment_image_url( $img, 'large' ) : '', ); } return $out; } /** * Seed the 24 default doors as CPT posts on activation (only if none exist). */ public static function seed_doors() { $existing = get_posts( array( 'post_type' => ADVK_Doors_CPT::POST_TYPE, 'post_status' => 'any', 'numberposts' => 1, 'fields' => 'ids', ) ); if ( ! empty( $existing ) ) { return; } foreach ( self::default_calendar() as $door ) { $post_id = wp_insert_post( array( 'post_type' => ADVK_Doors_CPT::POST_TYPE, 'post_status' => 'publish', 'post_title' => $door['sponsor'], 'menu_order' => $door['day'], ) ); if ( is_wp_error( $post_id ) || ! $post_id ) { continue; } update_post_meta( $post_id, '_advk_day', $door['day'] ); update_post_meta( $post_id, '_advk_sponsor_text', $door['sponsorText'] ); update_post_meta( $post_id, '_advk_prize', $door['prize'] ); update_post_meta( $post_id, '_advk_prize_text', $door['prizeText'] ); update_post_meta( $post_id, '_advk_value', $door['value'] ); update_post_meta( $post_id, '_advk_social', $door['social'] ); update_post_meta( $post_id, '_advk_quiz', $door['quiz'] ); } } }