0 ? max( self::BASELINE, $stored ) : self::BASELINE; } /** * Every step, keyed by the version it produces, in ascending order. * * @return array */ public static function steps(): array { /** * Filters the migration steps. * * @param array $steps Keyed by the version each one produces. */ $steps = (array) apply_filters( 'wpat_migrations', array() ); $callable = array(); foreach ( $steps as $version => $step ) { // Invalid steps are skipped so they cannot stop the ones after them. if ( (int) $version > 0 && is_callable( $step ) ) { $callable[ (int) $version ] = $step; } } ksort( $callable, SORT_NUMERIC ); return $callable; } /** * The steps that still have to run, in order. * * @return array */ public static function pending(): array { $from = self::current(); $due = array(); foreach ( self::steps() as $version => $step ) { if ( $version > $from ) { $due[ $version ] = $step; } } return $due; } /** * Whether anything is waiting to run. */ public static function is_pending(): bool { return ! empty( self::pending() ); } /** * Apply whatever is due. * * @return int[] The versions applied, in order. */ public static function run(): array { $applied = array(); foreach ( self::pending() as $version => $step ) { $step(); // Recorded after each step, so an interrupted run resumes instead of repeating one. self::remember( $version ); $applied[] = $version; } if ( empty( $applied ) ) { // Recorded even when nothing ran, or every request would look like a first run. self::remember( self::current() ); } return $applied; } /** * Note the shape the data is now in. */ private static function remember( int $version ): void { update_option( self::OPTION, $version ); } }