0 ) { $ids[] = $id; } } return array_values( array_unique( $ids ) ); } /** * Sanitizes a space separated list of CSS class names. * * @since 0.1 * * @param mixed $value Raw value. * @return string */ public static function to_class_list( $value ) { $classes = preg_split( '/\s+/', (string) $value, -1, PREG_SPLIT_NO_EMPTY ); if ( ! is_array( $classes ) ) { return ''; } $classes = array_filter( array_map( 'sanitize_html_class', $classes ) ); return implode( ' ', array_unique( $classes ) ); } /** * Clamps an integer between two bounds. * * @since 0.1 * * @param mixed $value Raw value. * @param int $min Lower bound. * @param int $max Upper bound. * @param int|null $fallback Value to use when $value is not numeric. Falls * back to $min when null. * @return int */ public static function clamp_int( $value, $min, $max, $fallback = null ) { if ( ! is_numeric( $value ) ) { // Falling back to $min would turn columns="four" into a one column // grid without saying so. The caller's fallback is the honest answer. $value = null === $fallback ? $min : $fallback; } return max( (int) $min, min( (int) $max, (int) $value ) ); } /** * Returns the box-shadow pair for a shadow preset. * * Presets are used instead of free text so that no arbitrary CSS can reach * the front end through the settings. * * @since 0.1 * * @param string $preset Preset key. * @return array{shadow:string,hover:string} */ public static function shadow( $preset ) { $presets = array( 'none' => array( 'shadow' => 'none', 'hover' => 'none', ), 'soft' => array( 'shadow' => '0 1px 2px rgba(24, 24, 43, 0.04)', 'hover' => '0 12px 28px -12px rgba(24, 24, 43, 0.22)', ), 'medium' => array( 'shadow' => '0 2px 6px rgba(24, 24, 43, 0.08)', 'hover' => '0 18px 36px -14px rgba(24, 24, 43, 0.28)', ), 'strong' => array( 'shadow' => '0 6px 16px rgba(24, 24, 43, 0.12)', 'hover' => '0 24px 48px -16px rgba(24, 24, 43, 0.34)', ), ); return isset( $presets[ $preset ] ) ? $presets[ $preset ] : $presets['soft']; } /** * Converts an aspect ratio preset to a CSS aspect-ratio value. * * @since 0.1 * * @param string $preset Preset key, for example `16-9`. * @return string */ public static function ratio( $preset ) { $presets = array( '16-9' => '16 / 9', '16-10' => '16 / 10', '3-2' => '3 / 2', '4-3' => '4 / 3', '1-1' => '1 / 1', '3-4' => '3 / 4', 'auto' => 'auto', ); return isset( $presets[ $preset ] ) ? $presets[ $preset ] : $presets['16-10']; } /** * Final guard for values printed inside a CSS declaration. * * Every value already comes from a typed setting, this only makes sure a * third party filter cannot inject declarations or close the style block. * * @since 0.1 * * @param string $value CSS value. * @return string */ public static function css_value( $value ) { $value = preg_replace( '/[^a-zA-Z0-9#%(),.\/ _-]/', '', (string) $value ); return trim( (string) $value ); } /** * Builds the visible page window for numbered pagination. * * Returns page numbers plus `null` placeholders where a gap should be shown. * * @since 0.1 * * @param int $current Current page. * @param int $total Total pages. * @param int $range How many pages to show on each side of the current one. * @return array */ public static function page_window( $current, $total, $range = 2 ) { $current = max( 1, (int) $current ); $total = max( 1, (int) $total ); $pages = array(); for ( $page = 1; $page <= $total; $page++ ) { $is_edge = 1 === $page || $total === $page; $in_window = abs( $current - $page ) <= $range; if ( $is_edge || $in_window ) { $pages[] = $page; } elseif ( ! empty( $pages ) && null !== end( $pages ) ) { $pages[] = null; } } return $pages; } }