0 ? $id : null; } if ( is_string( $id ) && preg_match( '/^[A-Za-z0-9_.:-]{1,64}$/', $id ) ) { if ( ctype_digit( $id ) && (int) $id === 0 ) { return null; } return $id; } return null; } /** Returns a list of clean fixes and a list of rejected ones (id may be null). */ public static function response( $data ) { $result = array( 'fixes' => array(), 'rejected' => array() ); if ( ! is_array( $data ) || ! isset( $data['fixes'] ) || ! is_array( $data['fixes'] ) ) { return $result; } foreach ( array_slice( array_values( $data['fixes'] ), 0, self::MAX_FIXES ) as $raw ) { $check = self::fix( $raw ); if ( $check['fix'] ) { $result['fixes'][] = $check['fix']; } else { $result['rejected'][] = array( 'id' => $check['id'], 'reason' => $check['reason'] ); } } return $result; } public static function fix( $raw ) { $bad = function ( $id, $reason ) { return array( 'fix' => null, 'id' => $id, 'reason' => $reason ); }; if ( ! is_array( $raw ) ) { return $bad( null, 'not an object' ); } $id = self::valid_id( isset( $raw['id'] ) ? $raw['id'] : null ); if ( $id === null ) { return $bad( null, 'bad id' ); } $kind = isset( $raw['kind'] ) && is_string( $raw['kind'] ) ? $raw['kind'] : ''; if ( ! in_array( $kind, self::KINDS, true ) ) { return $bad( $id, 'unknown kind' ); } return $kind === 'blog' ? self::blog( $id, $raw ) : self::meta( $id, $raw ); } private static function blog( $id, $raw ) { $title = Clientsask_Util::clean_text( isset( $raw['title'] ) ? $raw['title'] : '', 200 ); $html = isset( $raw['html'] ) && is_string( $raw['html'] ) ? Clientsask_Util::clip( $raw['html'], 200000 ) : ''; if ( $title === '' || trim( $html ) === '' ) { return array( 'fix' => null, 'id' => $id, 'reason' => 'blog needs title and html' ); } $slug = sanitize_title( Clientsask_Util::clean_text( isset( $raw['slug'] ) ? $raw['slug'] : '', 100 ) ); if ( $slug === '' ) { $slug = sanitize_title( $title ); } $faq = array(); if ( isset( $raw['faq'] ) && is_array( $raw['faq'] ) ) { foreach ( array_slice( array_values( $raw['faq'] ), 0, 12 ) as $item ) { $q = is_array( $item ) && isset( $item['q'] ) ? Clientsask_Util::clean_text( $item['q'], 300 ) : ''; $a = is_array( $item ) && isset( $item['a'] ) ? Clientsask_Util::clean_text( $item['a'], 1500 ) : ''; if ( $q !== '' && $a !== '' ) { $faq[] = array( 'q' => $q, 'a' => $a ); } } } return array( 'fix' => array( 'id' => $id, 'kind' => 'blog', 'title' => $title, 'slug' => $slug, 'metaTitle' => Clientsask_Util::clean_text( isset( $raw['metaTitle'] ) ? $raw['metaTitle'] : '', 120 ), 'metaDescription' => Clientsask_Util::clean_text( isset( $raw['metaDescription'] ) ? $raw['metaDescription'] : '', 320 ), 'html' => $html, 'faq' => $faq, 'jsonld' => self::clean_jsonld( isset( $raw['jsonld'] ) ? $raw['jsonld'] : '' ), ), 'id' => $id, 'reason' => '', ); } private static function meta( $id, $raw ) { $url = Clientsask_Util::clean_text( isset( $raw['url'] ) ? $raw['url'] : '', 2000 ); $parts = wp_parse_url( $url ); $ok = is_array( $parts ) && isset( $parts['scheme'], $parts['host'] ) && in_array( strtolower( $parts['scheme'] ), array( 'http', 'https' ), true ); $title = Clientsask_Util::clean_text( isset( $raw['title'] ) ? $raw['title'] : '', 200 ); $desc = Clientsask_Util::clean_text( isset( $raw['description'] ) ? $raw['description'] : '', 500 ); if ( ! $ok || $title === '' || $desc === '' ) { return array( 'fix' => null, 'id' => $id, 'reason' => 'meta needs url, title and description' ); } return array( 'fix' => array( 'id' => $id, 'kind' => 'meta', 'url' => $url, 'title' => $title, 'description' => $desc ), 'id' => $id, 'reason' => '', ); } /** * The FAQ JSON-LD must be JSON for one FAQPage and nothing else. Returns the re-encoded * text, or '' when it is not. Used again at print time (see Clientsask_Jsonld). */ public static function clean_jsonld( $text ) { if ( ! is_string( $text ) || $text === '' || strlen( $text ) > 50000 ) { return ''; } $data = json_decode( $text, true ); if ( ! is_array( $data ) || ! isset( $data['@type'] ) || $data['@type'] !== 'FAQPage' ) { return ''; } $out = wp_json_encode( $data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ); return is_string( $out ) ? $out : ''; } }