0 && mb_strlen( $text ) > $max_length ? mb_substr( $text, 0, $max_length ) : $text; } /** * Sanitizes a list of focus keywords: plain text, unique, at most five. * * @since 1.0.0 * * @param mixed $value Raw value. * @return string[] */ public static function keywords( $value ): array { if ( ! is_array( $value ) ) { return array(); } $keywords = array(); $seen = array(); foreach ( $value as $item ) { $keyword = self::text( $item, 100 ); $folded = function_exists( 'mb_strtolower' ) ? mb_strtolower( $keyword ) : strtolower( $keyword ); if ( '' === $keyword || isset( $seen[ $folded ] ) ) { continue; } $seen[ $folded ] = true; $keywords[] = $keyword; if ( count( $keywords ) >= 5 ) { break; } } return $keywords; } /** * Sanitizes the per-object robots settings. * * The five on/off directives are kept only when explicitly set, so "not set" (use the * site default) stays different from "false" (force index). The three limits must * be valid values. * * @since 1.0.0 * * @param mixed $value Raw value. * @return array */ public static function robots( $value ): array { if ( ! is_array( $value ) ) { return array(); } $clean = array(); foreach ( array( 'noindex', 'nofollow', 'noarchive', 'nosnippet', 'noimageindex' ) as $flag ) { if ( isset( $value[ $flag ] ) && '' !== $value[ $flag ] ) { $clean[ $flag ] = rest_sanitize_boolean( $value[ $flag ] ); } } $limits = array( 'max_snippet' => 'max-snippet', 'max_image_preview' => 'max-image-preview', 'max_video_preview' => 'max-video-preview', ); foreach ( $limits as $key => $directive ) { $limit = isset( $value[ $key ] ) ? self::robots_limit( $directive, $value[ $key ] ) : ''; if ( '' !== $limit ) { $clean[ $key ] = $limit; } } return $clean; } /** * Validates a max-snippet / max-image-preview / max-video-preview value. * * @since 1.0.0 * * @param string $directive Directive name such as `max-snippet`. * @param mixed $value Raw value. * @return string The value, or an empty string when it is not valid. */ public static function robots_limit( string $directive, $value ): string { if ( ! is_scalar( $value ) ) { return ''; } $value = strtolower( trim( (string) $value ) ); if ( 'max-image-preview' === $directive ) { return in_array( $value, array( 'none', 'standard', 'large' ), true ) ? $value : ''; } return 1 === preg_match( '/^(-1|\d{1,6})$/', $value ) ? $value : ''; } /** * Cleans the text of a robots.txt file. * * Tags are removed, line endings become "\n", control characters (other than tab and * newline) are dropped, trailing whitespace is trimmed from every line and the text is * cut to a maximum length. The result is plain text; it is sent as `text/plain`, never as HTML. * * @since 1.0.0 * * @param mixed $value Raw value. * @param int $max_length Maximum number of characters; 0 means no limit. * @return string */ public static function robots_txt( $value, int $max_length = 10000 ): string { if ( ! is_scalar( $value ) ) { return ''; } $text = wp_strip_all_tags( (string) $value, false ); $text = str_replace( array( "\r\n", "\r" ), "\n", $text ); $text = (string) preg_replace( '/[^\P{C}\t\n]/u', '', $text ); $text = (string) preg_replace( '/[ \t]+$/m', '', $text ); $text = trim( $text, "\n" ); if ( $max_length > 0 && mb_strlen( $text ) > $max_length ) { $text = rtrim( mb_substr( $text, 0, $max_length ) ); } return $text; } /** * Turns a list into unique positive integers. * * Accepts an array, or text with ids separated by commas, spaces or line breaks. * * @since 1.0.0 * * @param mixed $value Raw value. * @param int $max Maximum number of ids to keep. * @return int[] */ public static function ids( $value, int $max = 1000 ): array { if ( is_string( $value ) ) { $value = preg_split( '/[\s,;]+/', $value, -1, PREG_SPLIT_NO_EMPTY ); } if ( ! is_array( $value ) ) { return array(); } $ids = array(); foreach ( $value as $item ) { if ( ! is_scalar( $item ) || 1 !== preg_match( '/^\d{1,10}$/', trim( (string) $item ) ) ) { continue; } $id = (int) $item; if ( $id > 0 ) { $ids[ $id ] = $id; } if ( count( $ids ) >= $max ) { break; } } return array_values( $ids ); } }