This commit is contained in:
Javier Casares 2026-08-10 14:03:36 +00:00
commit 3bb9ed33e1
12 changed files with 1762 additions and 409 deletions

View file

@ -23,6 +23,29 @@ if ( ! defined( 'ABSPATH' ) ) {
*/
class Robotstxt_OG_Meta_Box {
/**
* Allowed og:type override values (the auto-derived default is stored as empty).
*
* @since 1.2.0
* @var string[]
*/
public const ALLOWED_OG_TYPES = array( 'website', 'article' );
/**
* Sanitize an og:type override value to a safe value or empty string.
*
* @since 1.2.0
*
* @param mixed $value Raw value.
* @return string
*/
public static function sanitize_og_type( $value ): string {
$value = is_string( $value ) ? $value : '';
return in_array( $value, self::ALLOWED_OG_TYPES, true ) ? $value : '';
}
/**
* Initialize hooks.
*
@ -82,6 +105,48 @@ class Robotstxt_OG_Meta_Box {
'show_in_rest' => true,
)
);
register_post_meta(
$post_type,
'_og_image_alt',
array(
'type' => 'string',
'single' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => static function () {
return current_user_can( 'edit_posts' );
},
'show_in_rest' => true,
)
);
register_post_meta(
$post_type,
'_og_type',
array(
'type' => 'string',
'single' => true,
'sanitize_callback' => array( __CLASS__, 'sanitize_og_type' ),
'auth_callback' => static function () {
return current_user_can( 'edit_posts' );
},
'show_in_rest' => true,
)
);
register_post_meta(
$post_type,
'_twitter_creator',
array(
'type' => 'string',
'single' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => static function () {
return current_user_can( 'edit_posts' );
},
'show_in_rest' => true,
)
);
}
}
@ -118,14 +183,62 @@ class Robotstxt_OG_Meta_Box {
public function render_meta_box( WP_Post $post ): void {
wp_nonce_field( 'robotstxt_og_meta_box', 'robotstxt_og_meta_box_nonce' );
$raw_title = get_post_meta( $post->ID, '_og_title', true );
$og_title = is_string( $raw_title ) ? $raw_title : '';
$raw_desc = get_post_meta( $post->ID, '_og_description', true );
$og_description = is_string( $raw_desc ) ? $raw_desc : '';
$raw_title = get_post_meta( $post->ID, '_og_title', true );
$og_title = is_string( $raw_title ) ? $raw_title : '';
$raw_desc = get_post_meta( $post->ID, '_og_description', true );
$og_description = is_string( $raw_desc ) ? $raw_desc : '';
$raw_alt = get_post_meta( $post->ID, '_og_image_alt', true );
$og_image_alt = is_string( $raw_alt ) ? $raw_alt : '';
$raw_type = get_post_meta( $post->ID, '_og_type', true );
$og_type = self::sanitize_og_type( $raw_type );
$raw_creator = get_post_meta( $post->ID, '_twitter_creator', true );
$twitter_creator = is_string( $raw_creator ) ? $raw_creator : '';
?>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row">
<label for="robotstxt_og_type">
<?php esc_html_e( 'Open Graph Type', 'robotstxt-og' ); ?>
</label>
</th>
<td>
<select id="robotstxt_og_type" name="robotstxt_og_type">
<option value="" <?php selected( $og_type, '' ); ?>>
<?php esc_html_e( 'Default (auto: article for posts, website otherwise)', 'robotstxt-og' ); ?>
</option>
<option value="website" <?php selected( $og_type, 'website' ); ?>>
<?php esc_html_e( 'website', 'robotstxt-og' ); ?>
</option>
<option value="article" <?php selected( $og_type, 'article' ); ?>>
<?php esc_html_e( 'article', 'robotstxt-og' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Overrides og:type for this post. Selecting "article" also emits the article:* meta tags (published/modified time, section, tags).', 'robotstxt-og' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="robotstxt_og_twitter_creator">
<?php esc_html_e( 'Twitter Author Handle', 'robotstxt-og' ); ?>
</label>
</th>
<td>
<input
type="text"
id="robotstxt_og_twitter_creator"
name="robotstxt_og_twitter_creator"
value="<?php echo esc_attr( $twitter_creator ); ?>"
class="large-text"
placeholder="@username"
/>
<p class="description">
<?php esc_html_e( 'Twitter/X handle of the post author, emitted as twitter:creator. Leave blank to omit.', 'robotstxt-og' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="robotstxt_og_title">
@ -163,6 +276,25 @@ class Robotstxt_OG_Meta_Box {
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="robotstxt_og_image_alt">
<?php esc_html_e( 'Custom OG Image Alt', 'robotstxt-og' ); ?>
</label>
</th>
<td>
<input
type="text"
id="robotstxt_og_image_alt"
name="robotstxt_og_image_alt"
value="<?php echo esc_attr( $og_image_alt ); ?>"
class="large-text"
/>
<p class="description">
<?php esc_html_e( 'Alt text for the og:image of this post. Leave blank to use the featured image alt text from the media library.', 'robotstxt-og' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
<?php
@ -217,5 +349,35 @@ class Robotstxt_OG_Meta_Box {
} else {
update_post_meta( $post_id, '_og_description', $og_desc );
}
// Save og:image:alt.
$og_alt_raw = filter_input( INPUT_POST, 'robotstxt_og_image_alt', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$og_alt = $og_alt_raw ? sanitize_text_field( wp_unslash( $og_alt_raw ) ) : '';
if ( empty( $og_alt ) ) {
delete_post_meta( $post_id, '_og_image_alt' );
} else {
update_post_meta( $post_id, '_og_image_alt', $og_alt );
}
// Save og:type override (whitelisted).
$og_type_raw = filter_input( INPUT_POST, 'robotstxt_og_type', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$og_type = self::sanitize_og_type( $og_type_raw ? wp_unslash( $og_type_raw ) : '' );
if ( '' === $og_type ) {
delete_post_meta( $post_id, '_og_type' );
} else {
update_post_meta( $post_id, '_og_type', $og_type );
}
// Save twitter:creator handle.
$creator_raw = filter_input( INPUT_POST, 'robotstxt_og_twitter_creator', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$creator = $creator_raw ? sanitize_text_field( wp_unslash( $creator_raw ) ) : '';
if ( '' === $creator ) {
delete_post_meta( $post_id, '_twitter_creator' );
} else {
update_post_meta( $post_id, '_twitter_creator', $creator );
}
}
}