type */ public static function defs() { return array( 'title' => 'text', 'desc' => 'textarea', 'focus' => 'text', 'keywords' => 'text', 'noindex' => 'bool', 'nofollow' => 'bool', 'noarchive' => 'bool', 'nosnippet' => 'bool', 'noimageindex' => 'bool', 'canonical' => 'url', 'exclude_sitemap' => 'bool', 'schema_type' => 'text', 'og_title' => 'text', 'og_desc' => 'textarea', 'og_image' => 'url', 'faq' => 'faq', ); } public static function hook() { foreach ( self::defs() as $key => $type ) { register_post_meta( '', self::PREFIX . $key, array( 'show_in_rest' => false, 'single' => true, 'type' => 'faq' === $type ? 'array' : 'string', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); } add_action( 'save_post', array( __CLASS__, 'touch_score' ), 20, 2 ); } public static function get( $post_id, $key ) { $v = get_post_meta( $post_id, self::PREFIX . $key, true ); if ( 'faq' === ( self::defs()[ $key ] ?? '' ) ) { return is_array( $v ) ? $v : array(); } return is_string( $v ) ? $v : ''; } public static function sanitize( $key, $value ) { $type = self::defs()[ $key ] ?? 'text'; switch ( $type ) { case 'bool': return $value ? '1' : ''; case 'url': return esc_url_raw( (string) $value ); case 'textarea': return sanitize_textarea_field( (string) $value ); case 'faq': $rows = array(); foreach ( (array) $value as $r ) { $q = sanitize_text_field( $r['q'] ?? '' ); $a = sanitize_textarea_field( $r['a'] ?? '' ); if ( '' !== $q && '' !== $a ) { $rows[] = array( 'q' => $q, 'a' => $a ); } } return array_slice( $rows, 0, 20 ); default: return sanitize_text_field( (string) $value ); } } /** Save any subset of fields. Empty value deletes the meta (= back to automatic). */ public static function save( $post_id, array $values ) { foreach ( self::defs() as $key => $type ) { if ( ! array_key_exists( $key, $values ) ) { continue; } $v = self::sanitize( $key, $values[ $key ] ); if ( '' === $v || array() === $v ) { delete_post_meta( $post_id, self::PREFIX . $key ); } else { update_post_meta( $post_id, self::PREFIX . $key, $v ); } } delete_post_meta( $post_id, '_sxseo_score' ); SXSEO_Sitemap::purge(); } public static function all_custom( $post_id ) { $out = array(); foreach ( array_keys( self::defs() ) as $k ) { $out[ $k ] = self::get( $post_id, $k ); } return $out; } /** Invalidate the cached score whenever the post changes. */ public static function touch_score( $post_id, $post ) { if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) { return; } delete_post_meta( $post_id, '_sxseo_score' ); } }