This commit is contained in:
Javier Casares 2026-03-28 07:59:52 +00:00
commit ddaaff71ad
23 changed files with 879 additions and 798 deletions

View file

@ -54,6 +54,24 @@ class Robotstxt_OG_Admin_Settings {
add_action( 'admin_init', array( $this, 'handle_resolve_all' ) );
add_action( 'admin_init', array( $this, 'handle_clear_single' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
// Allow editors (edit_others_posts) to save settings via the Settings API.
// options.php defaults to manage_options; this filter lowers it for our group.
add_filter( 'option_page_capability_robotstxt_og_settings', array( $this, 'get_settings_capability' ) );
}
/**
* Return the capability required to save plugin settings.
*
* Allows users with edit_others_posts (editors and above) to save plugin
* settings through the WordPress Settings API (options.php).
*
* @since 1.0.3
*
* @return string Capability slug.
*/
public function get_settings_capability(): string {
return 'edit_others_posts';
}
/**
@ -77,7 +95,7 @@ class Robotstxt_OG_Admin_Settings {
}
// Verify nonce.
$nonce_raw = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_SPECIAL_CHARS );
$nonce_raw = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$nonce = $nonce_raw ? sanitize_text_field( wp_unslash( $nonce_raw ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'robotstxt_og_clear_single_' . $post_id ) ) {
@ -85,7 +103,7 @@ class Robotstxt_OG_Admin_Settings {
}
// Check permissions.
if ( ! current_user_can( 'manage_options' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'robotstxt-og' ) );
}
@ -120,7 +138,7 @@ class Robotstxt_OG_Admin_Settings {
add_options_page(
__( 'OpenGraph Settings', 'robotstxt-og' ),
__( 'OpenGraph', 'robotstxt-og' ),
'manage_options',
'edit_others_posts',
'robotstxt-og-settings',
array( $this, 'render_settings_page' )
);
@ -344,7 +362,8 @@ class Robotstxt_OG_Admin_Settings {
* @return void
*/
public function render_fallback_image_field(): void {
$image_url = (string) get_option( 'robotstxt_og_fallback_image', '' );
$option_value = get_option( 'robotstxt_og_fallback_image', '' );
$image_url = is_string( $option_value ) ? $option_value : '';
?>
<input
type="url"
@ -368,7 +387,8 @@ class Robotstxt_OG_Admin_Settings {
* @return void
*/
public function render_homepage_image_field(): void {
$image_url = (string) get_option( 'robotstxt_og_homepage_image', '' );
$option_value = get_option( 'robotstxt_og_homepage_image', '' );
$image_url = is_string( $option_value ) ? $option_value : '';
?>
<input
type="url"
@ -492,7 +512,8 @@ class Robotstxt_OG_Admin_Settings {
* @return void
*/
public function render_twitter_site_field(): void {
$handle = (string) get_option( 'robotstxt_og_twitter_site', '' );
$option_value = get_option( 'robotstxt_og_twitter_site', '' );
$handle = is_string( $option_value ) ? $option_value : '';
?>
<input
type="text"
@ -517,7 +538,7 @@ class Robotstxt_OG_Admin_Settings {
*/
public function render_settings_page(): void {
// Check user capabilities.
if ( ! current_user_can( 'manage_options' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'robotstxt-og' ) );
}
@ -534,13 +555,13 @@ class Robotstxt_OG_Admin_Settings {
*/
public function handle_clear_cache(): void {
// Check if this is a cache clear request.
$clear_cache = filter_input( INPUT_GET, 'robotstxt_og_clear_cache', FILTER_SANITIZE_SPECIAL_CHARS );
$clear_cache = filter_input( INPUT_GET, 'robotstxt_og_clear_cache', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
if ( null === $clear_cache ) {
return;
}
// Verify nonce.
$nonce_raw = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_SPECIAL_CHARS );
$nonce_raw = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$nonce = $nonce_raw ? sanitize_text_field( wp_unslash( $nonce_raw ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'robotstxt_og_clear_cache' ) ) {
@ -548,7 +569,7 @@ class Robotstxt_OG_Admin_Settings {
}
// Check permissions.
if ( ! current_user_can( 'manage_options' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'robotstxt-og' ) );
}
@ -581,13 +602,13 @@ class Robotstxt_OG_Admin_Settings {
*/
public function handle_resolve_all(): void {
// Check if this is a resolve all request.
$resolve_all = filter_input( INPUT_GET, 'robotstxt_og_resolve_all', FILTER_SANITIZE_SPECIAL_CHARS );
$resolve_all = filter_input( INPUT_GET, 'robotstxt_og_resolve_all', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
if ( null === $resolve_all ) {
return;
}
// Verify nonce.
$nonce_raw = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_SPECIAL_CHARS );
$nonce_raw = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$nonce = $nonce_raw ? sanitize_text_field( wp_unslash( $nonce_raw ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'robotstxt_og_resolve_all' ) ) {
@ -595,7 +616,7 @@ class Robotstxt_OG_Admin_Settings {
}
// Check permissions.
if ( ! current_user_can( 'manage_options' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'robotstxt-og' ) );
}

View file

@ -15,7 +15,8 @@ if ( ! defined( 'ABSPATH' ) ) {
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'settings';
$tab_raw = isset( $_GET['tab'] ) && is_string( $_GET['tab'] ) ? $_GET['tab'] : '';
$active_tab = $tab_raw ? sanitize_key( wp_unslash( $tab_raw ) ) : 'settings';
$valid_tabs = array( 'settings', 'tools', 'diagnostics' );
if ( ! in_array( $active_tab, $valid_tabs, true ) ) {
@ -174,7 +175,8 @@ $page_url = admin_url( 'options-general.php?page=robotstxt-og-settings' );
$posts_per_page = 20;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$current_page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1;
$paged_raw = isset( $_GET['paged'] ) && is_string( $_GET['paged'] ) ? $_GET['paged'] : '';
$current_page = $paged_raw ? max( 1, absint( $paged_raw ) ) : 1;
$offset = ( $current_page - 1 ) * $posts_per_page;
$total_pages = (int) ceil( $total_cached / $posts_per_page );
@ -237,7 +239,8 @@ $page_url = admin_url( 'options-general.php?page=robotstxt-og-settings' );
<td>
<?php
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$test_url_raw = isset( $_GET['test_url'] ) ? esc_url_raw( wp_unslash( $_GET['test_url'] ) ) : '';
$test_url_input = isset( $_GET['test_url'] ) && is_string( $_GET['test_url'] ) ? $_GET['test_url'] : '';
$test_url_raw = $test_url_input ? esc_url_raw( wp_unslash( $test_url_input ) ) : '';
?>
<input
type="url"
@ -289,7 +292,14 @@ $page_url = admin_url( 'options-general.php?page=robotstxt-og-settings' );
echo '<th>' . esc_html__( 'Value', 'robotstxt-og' ) . '</th></tr></thead><tbody>';
foreach ( $headers as $header_key => $header_value ) {
echo '<tr><td><code>' . esc_html( $header_key ) . '</code></td>';
echo '<td>' . esc_html( is_array( $header_value ) ? implode( ', ', $header_value ) : $header_value ) . '</td></tr>';
if ( is_array( $header_value ) ) {
$display_value = implode( ', ', array_map( static fn( $v ) => is_scalar( $v ) ? (string) $v : '', $header_value ) );
} elseif ( is_string( $header_value ) ) {
$display_value = $header_value;
} else {
$display_value = '';
}
echo '<td>' . esc_html( $display_value ) . '</td></tr>';
}
echo '</tbody></table>';
}
@ -324,7 +334,7 @@ $page_url = admin_url( 'options-general.php?page=robotstxt-og-settings' );
<tr>
<td><?php echo absint( $cached_entry->post_id ); ?></td>
<td>
<a href="<?php echo esc_url( get_edit_post_link( $cached_entry->post_id ) ); ?>">
<a href="<?php echo esc_url( get_edit_post_link( $cached_entry->post_id ) ?? '' ); ?>">
<?php echo esc_html( $cached_entry->post_title ); ?>
</a>
</td>