sub( new DateInterval( 'P17Y' ) ); $born = new DateTimeImmutable( sprintf( '%04d-%02d-%02d', $parsed['year'], $parsed['month'], $parsed['day'] ), $timezone ); // Positive when older than 17; negative when younger. Same framing as the original plugin. return (int) $born->diff( $base )->format( '%r%a' ); } /** * Render year / month / day select controls. * * @param string|null $birthday Stored birth date or null for default (today − 17 years). * @return string HTML (escaped). */ public static function render_selects( ?string $birthday ): string { $timezone = wp_timezone(); $default = ( new DateTimeImmutable( 'today', $timezone ) )->sub( new DateInterval( 'P17Y' ) ); $parsed = null !== $birthday ? self::parse( $birthday ) : null; $year = $parsed['year'] ?? (int) $default->format( 'Y' ); $month = $parsed['month'] ?? (int) $default->format( 'n' ); $day = $parsed['day'] ?? (int) $default->format( 'j' ); $current_year = (int) ( new DateTimeImmutable( 'now', $timezone ) )->format( 'Y' ); $min_year = $current_year - 100; $year_html = ''; $month_html = ''; $day_html = ''; return $year_html . ' - ' . $month_html . ' - ' . $day_html; } /** * Parse a Y-n-j (or similar) date string into components. * * @param string $value Raw date string. * @return array{year:int,month:int,day:int}|null */ private static function parse( string $value ): ?array { if ( ! preg_match( '/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value, $matches ) ) { return null; } $year = (int) $matches[1]; $month = (int) $matches[2]; $day = (int) $matches[3]; if ( ! checkdate( $month, $day, $year ) ) { return null; } return array( 'year' => $year, 'month' => $month, 'day' => $day, ); } }