offset = 0; $batch_size = (int) apply_filters( 'tec_events_category_color_generator_batch_size', 500 ); $categories = []; do { $results = $db->table( 'term_taxonomy', 'tt' ) ->select( 'tm.term_id', 'tm.meta_key', 'tm.meta_value', 't.slug' ) ->innerJoin( 'termmeta', 'tt.term_id', 'tm.term_id', 'tm' ) ->innerJoin( 'terms', 'tt.term_id', 't.term_id', 't' ) ->where( 'tt.taxonomy', Tribe__Events__Main::TAXONOMY ) ->whereIn( 'tm.meta_key', $this->get_all_keys() ) ->limit( $batch_size ) ->offset( $offset ) ->getAll(); if ( ! empty( $results ) ) { foreach ( $results as $row ) { $term_id = (int) $row->term_id; $slug = sanitize_title( $row->slug ); $meta_key = $row->meta_key; $meta_value = $row->meta_value; if ( ! isset( $categories[ $term_id ] ) ) { $categories[ $term_id ] = [ 'slug' => $slug, 'primary' => '', 'background' => '', 'text' => '', 'priority' => -1, ]; } switch ( $meta_key ) { case $this->get_key( 'primary' ): $categories[ $term_id ]['primary'] = $meta_value; break; case $this->get_key( 'secondary' ): $categories[ $term_id ]['background'] = $meta_value; break; case $this->get_key( 'text' ): $categories[ $term_id ]['text'] = $meta_value; break; case $this->get_key( 'priority' ): $categories[ $term_id ]['priority'] = is_numeric( $meta_value ) ? (int) $meta_value : -1; break; } } } $offset += $batch_size; } while ( ! empty( $results ) ); // Sort by priority ascending (lower priority first, highest priority last). usort( $categories, fn( $a, $b ) => $a['priority'] <=> $b['priority'] ); return $categories; } /** * Minify the generated CSS by removing spaces, newlines, and comments. * * @since 6.14.0 */ public function minify_css(): void { $comments = <<<'EOS' (?sx) # Don't change anything inside of quotes ( "(?:[^"\\]++|\\.)*+" | '(?:[^'\\]++|\\.)*+' ) | # Remove CSS comments /\* (?> .*? \*/ ) EOS; $everything_else = <<<'EOS' (?six) # Don't change anything inside of quotes ( "(?:[^"\\]++|\\.)*+" | '(?:[^'\\]++|\\.)*+' ) | # Remove spaces before and after ; and } \s*+ ; \s*+ ( } ) \s*+ | # Remove all spaces around meta chars/operators (excluding + and -) \s*+ ( [*$~^|]?+= | [{};,>~] | !important\b ) \s*+ | # Remove all spaces around + and - (in selectors only!) \s*([+-])\s*(?=[^}]*{) | # Remove spaces right of ( [ : ( [[(:] ) \s++ | # Remove spaces left of ) ] \s++ ( [])] ) | # Remove spaces left (and right) of : (but not in selectors!) \s+(:)(?![^\}]*\{) | # Remove spaces at beginning/end of string ^ \s++ | \s++ \z | # Convert double spaces to single (\s)\s+ EOS; $search_patterns = [ "%{$comments}%", "%{$everything_else}%" ]; $replace_patterns = [ '$1', '$1$2$3$4$5$6$7$8' ]; $this->generated_css = preg_replace( $search_patterns, $replace_patterns, $this->generated_css ); } /** * Sanitizes a HEX color string and optionally validates its format. * * Accepts a HEX, RGB, or HSL color input and attempts to parse it as a HEX color using * the Tribe Color utility. Returns a sanitized HEX color with a leading hash (`#`) if valid. * * If `$validate` is true, the resulting HEX value is checked for proper format before returning. * * @since 6.14.0 * * @param string|null $color The color input. * @param bool $validate Whether to validate the color before converting. * * @return string|null The sanitized HEX color or null if invalid. */ protected function sanitize_color( ?string $color, bool $validate = false ): ?string { if ( is_null( $color ) ) { return null; } try { $color_obj = new Tribe__Utils__Color( $color ); $hex = $color_obj->get_hex_with_hash(); // Ensure we always return HEX format. return ( $validate && ! $this->is_valid_hex( $hex ) ) ? null : $hex; } catch ( \Exception $e ) { return null; // Invalid color formats (bad RGB, HSL, etc.). } } /** * Validate if a string is a proper hex color. * * @since 6.14.0 * * @param string|null $color The color string. * * @return bool True if valid, false otherwise. */ protected function is_valid_hex( ?string $color ): bool { return ! empty( $color ) && preg_match( '/^#([0-9a-f]{6}|[0-9a-f]{3})$/i', $color ); } }