'_yoast_wpseo_title', 'metadesc' => '_yoast_wpseo_metadesc', 'focuskw' => '_yoast_wpseo_focuskw', 'focuskeywords' => '_yoast_wpseo_focuskeywords', 'keywordsynonyms' => '_yoast_wpseo_keywordsynonyms', 'meta-robots-noindex' => '_yoast_wpseo_meta-robots-noindex', 'meta-robots-nofollow' => '_yoast_wpseo_meta-robots-nofollow', 'meta-robots-adv' => '_yoast_wpseo_meta-robots-adv', 'canonical' => '_yoast_wpseo_canonical', 'redirect' => '_yoast_wpseo_redirect', 'is_cornerstone' => '_yoast_wpseo_is_cornerstone', 'opengraph-title' => '_yoast_wpseo_opengraph-title', 'opengraph-description' => '_yoast_wpseo_opengraph-description', 'opengraph-image' => '_yoast_wpseo_opengraph-image', 'opengraph-image-id' => '_yoast_wpseo_opengraph-image-id', 'twitter-title' => '_yoast_wpseo_twitter-title', 'twitter-description' => '_yoast_wpseo_twitter-description', 'twitter-image' => '_yoast_wpseo_twitter-image', 'twitter-image-id' => '_yoast_wpseo_twitter-image-id', 'schema_page_type' => '_yoast_wpseo_schema_page_type', 'schema_article_type' => '_yoast_wpseo_schema_article_type', 'linkdex' => '_yoast_wpseo_linkdex', 'content_score' => '_yoast_wpseo_content_score', 'primary_category' => '_yoast_wpseo_primary_category', ); } /** * Sanitize Yoast meta value based on field type. * * @since 1.0.0 * @param string $key Field key. * @param mixed $value Value to sanitize. * @return mixed Sanitized value. */ function a1tools_sanitize_yoast_value( $key, $value ) { $json_fields = array( 'focuskeywords', 'keywordsynonyms' ); if ( in_array( $key, $json_fields, true ) ) { if ( is_array( $value ) ) { return wp_json_encode( $value ); } if ( is_string( $value ) ) { $decoded = json_decode( $value ); if ( JSON_ERROR_NONE === json_last_error() ) { return $value; } return wp_json_encode( array( $value ) ); } return ''; } $bool_fields = array( 'is_cornerstone', 'meta-robots-noindex', 'meta-robots-nofollow' ); if ( in_array( $key, $bool_fields, true ) ) { return $value ? '1' : '0'; } $int_fields = array( 'linkdex', 'content_score', 'primary_category', 'opengraph-image-id', 'twitter-image-id' ); if ( in_array( $key, $int_fields, true ) ) { return (int) $value; } $url_fields = array( 'canonical', 'redirect', 'opengraph-image', 'twitter-image' ); if ( in_array( $key, $url_fields, true ) ) { return esc_url_raw( $value ); } $text_fields = array( 'title', 'metadesc', 'opengraph-title', 'opengraph-description', 'twitter-title', 'twitter-description' ); if ( in_array( $key, $text_fields, true ) ) { return sanitize_text_field( $value ); } if ( is_string( $value ) ) { return sanitize_text_field( $value ); } return $value; } /** * Update Yoast SEO meta fields for a post. * * @since 1.0.0 * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object. */ function a1tools_update_yoast_meta( $request ) { $post_id = (int) $request['id']; $post = get_post( $post_id ); if ( ! $post ) { return new WP_Error( 'post_not_found', __( 'Post not found', 'a1-tools' ), array( 'status' => 404 ) ); } if ( ! current_user_can( 'edit_post', $post_id ) ) { return new WP_Error( 'forbidden', __( 'You do not have permission to edit this post', 'a1-tools' ), array( 'status' => 403 ) ); } $body = $request->get_json_params(); if ( empty( $body ) ) { return new WP_Error( 'no_data', __( 'No data provided', 'a1-tools' ), array( 'status' => 400 ) ); } $mapping = a1tools_get_yoast_meta_mapping(); $updated = array(); $errors = array(); foreach ( $body as $key => $value ) { if ( isset( $mapping[ $key ] ) ) { $meta_key = $mapping[ $key ]; } elseif ( 0 === strpos( $key, '_yoast_wpseo_' ) ) { $meta_key = $key; } else { continue; } $sanitized_value = a1tools_sanitize_yoast_value( $key, $value ); $result = update_post_meta( $post_id, $meta_key, $sanitized_value ); if ( false !== $result ) { $updated[ $key ] = $sanitized_value; } else { $current_value = get_post_meta( $post_id, $meta_key, true ); if ( $current_value === $sanitized_value || $current_value === (string) $sanitized_value ) { $updated[ $key ] = $sanitized_value; } else { $errors[ $key ] = 'Failed to update'; } } } if ( class_exists( 'WPSEO_Meta' ) ) { // Trigger Yoast SEO's native action hook to refresh their internal cache. // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- This is Yoast's hook, not ours. do_action( 'wpseo_saved_postdata' ); } return new WP_REST_Response( array( 'success' => true, 'post_id' => $post_id, 'updated' => $updated, 'errors' => $errors, ), 200 ); } /** * Get Yoast SEO meta fields for a post. * * @since 1.0.0 * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object. */ function a1tools_get_yoast_meta( $request ) { $post_id = (int) $request['id']; $post = get_post( $post_id ); if ( ! $post ) { return new WP_Error( 'post_not_found', __( 'Post not found', 'a1-tools' ), array( 'status' => 404 ) ); } $mapping = a1tools_get_yoast_meta_mapping(); $meta = array(); foreach ( $mapping as $api_key => $meta_key ) { $value = get_post_meta( $post_id, $meta_key, true ); if ( '' !== $value && false !== $value ) { $meta[ $api_key ] = $value; } } return new WP_REST_Response( array( 'success' => true, 'post_id' => $post_id, 'meta' => $meta, ), 200 ); }