165 lines
4.0 KiB
PHP
165 lines
4.0 KiB
PHP
<?php
|
||
/**
|
||
* Handles saving and retrieving SEO meta for posts, pages and custom post types.
|
||
*
|
||
* @package S1_SEO_Meta
|
||
*/
|
||
|
||
if ( ! defined( 'ABSPATH' ) ) {
|
||
exit;
|
||
}
|
||
|
||
class S1_SEO_Meta_Post {
|
||
|
||
/**
|
||
* Meta key for SEO title.
|
||
*/
|
||
const META_TITLE = '_s1_seo_title';
|
||
|
||
/**
|
||
* Meta key for SEO description.
|
||
*/
|
||
const META_DESC = '_s1_seo_description';
|
||
|
||
public function __construct() {
|
||
add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
|
||
add_action( 'save_post', array( $this, 'save_meta' ), 10, 2 );
|
||
}
|
||
|
||
/**
|
||
* Register the meta box for all public post types.
|
||
*/
|
||
public function add_meta_box() {
|
||
$post_types = get_post_types( array( 'public' => true ), 'names' );
|
||
|
||
foreach ( $post_types as $post_type ) {
|
||
add_meta_box(
|
||
's1-seo-meta-box',
|
||
__( 'S1 SEO: Title & Description', 's1-seo-meta' ),
|
||
array( $this, 'render_meta_box' ),
|
||
$post_type,
|
||
'normal',
|
||
'high'
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Render the meta box HTML.
|
||
*
|
||
* @param WP_Post $post Current post object.
|
||
*/
|
||
public function render_meta_box( $post ) {
|
||
wp_nonce_field( 's1_seo_meta_save', 's1_seo_meta_nonce' );
|
||
|
||
$seo_title = get_post_meta( $post->ID, self::META_TITLE, true );
|
||
$seo_desc = get_post_meta( $post->ID, self::META_DESC, true );
|
||
?>
|
||
<div class="s1-seo-wrap">
|
||
<div class="s1-seo-field">
|
||
<label for="s1_seo_title">
|
||
<?php esc_html_e( 'SEO Title', 's1-seo-meta' ); ?>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
id="s1_seo_title"
|
||
name="s1_seo_title"
|
||
value="<?php echo esc_attr( $seo_title ); ?>"
|
||
placeholder="<?php echo esc_attr( get_the_title( $post->ID ) ); ?>"
|
||
maxlength="666"
|
||
/>
|
||
<div class="s1-seo-counter">
|
||
<span class="s1-seo-count" id="s1_seo_title_count">0</span>/60
|
||
<?php esc_html_e( 'characters (recommended: 50–60)', 's1-seo-meta' ); ?>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="s1-seo-field">
|
||
<label for="s1_seo_description">
|
||
<?php esc_html_e( 'SEO Description', 's1-seo-meta' ); ?>
|
||
</label>
|
||
<textarea
|
||
id="s1_seo_description"
|
||
name="s1_seo_description"
|
||
rows="3"
|
||
maxlength="666"
|
||
placeholder="<?php esc_attr_e( 'Write a short description of this page…', 's1-seo-meta' ); ?>"
|
||
><?php echo esc_textarea( $seo_desc ); ?></textarea>
|
||
<div class="s1-seo-counter">
|
||
<span class="s1-seo-count" id="s1_seo_desc_count">0</span>/160
|
||
<?php esc_html_e( 'characters (recommended: 120–160)', 's1-seo-meta' ); ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
/**
|
||
* Save SEO meta fields when the post is saved.
|
||
*
|
||
* @param int $post_id Post ID.
|
||
* @param WP_Post $post Post object.
|
||
*/
|
||
public function save_meta( $post_id, $post ) {
|
||
// Verify nonce.
|
||
if (
|
||
! isset( $_POST['s1_seo_meta_nonce'] ) ||
|
||
! wp_verify_nonce( sanitize_key( $_POST['s1_seo_meta_nonce'] ), 's1_seo_meta_save' )
|
||
) {
|
||
return;
|
||
}
|
||
|
||
// Skip autosaves and revisions.
|
||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||
return;
|
||
}
|
||
if ( wp_is_post_revision( $post_id ) ) {
|
||
return;
|
||
}
|
||
|
||
// Check permissions.
|
||
$post_type_obj = get_post_type_object( $post->post_type );
|
||
if ( ! current_user_can( $post_type_obj->cap->edit_post, $post_id ) ) {
|
||
return;
|
||
}
|
||
|
||
// Save title.
|
||
if ( isset( $_POST['s1_seo_title'] ) ) {
|
||
update_post_meta(
|
||
$post_id,
|
||
self::META_TITLE,
|
||
sanitize_text_field( wp_unslash( $_POST['s1_seo_title'] ) )
|
||
);
|
||
}
|
||
|
||
// Save description.
|
||
if ( isset( $_POST['s1_seo_description'] ) ) {
|
||
update_post_meta(
|
||
$post_id,
|
||
self::META_DESC,
|
||
sanitize_textarea_field( wp_unslash( $_POST['s1_seo_description'] ) )
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Static helper: retrieve SEO title for a given post.
|
||
*
|
||
* @param int $post_id Post ID.
|
||
* @return string
|
||
*/
|
||
public static function get_title( $post_id ) {
|
||
return (string) get_post_meta( $post_id, self::META_TITLE, true );
|
||
}
|
||
|
||
/**
|
||
* Static helper: retrieve SEO description for a given post.
|
||
*
|
||
* @param int $post_id Post ID.
|
||
* @return string
|
||
*/
|
||
public static function get_description( $post_id ) {
|
||
return (string) get_post_meta( $post_id, self::META_DESC, true );
|
||
}
|
||
}
|