2023-11-23 14:10:48 +01:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Class used to create a new options page.
|
2023-11-23 15:02:36 +01:00
|
|
|
*
|
|
|
|
* @package WP_Options_Page
|
|
|
|
* @author Mikael Fourré
|
2025-08-12 07:29:03 +02:00
|
|
|
* @version 1.3.1
|
2023-11-23 15:02:36 +01:00
|
|
|
* @see https://github.com/FmiKL/wp-options-page
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
class Option_Page {
|
2023-11-23 14:58:52 +01:00
|
|
|
/**
|
|
|
|
* Path to the assets.
|
|
|
|
*
|
|
|
|
* @var string
|
2023-11-23 15:02:36 +01:00
|
|
|
* @since 1.0.0
|
|
|
|
* @see Option_Page::enqueues_scripts()
|
2023-11-23 14:58:52 +01:00
|
|
|
*/
|
2023-11-27 19:08:31 +01:00
|
|
|
private const ASSETS_PATH = '/wp-options-page/assets';
|
2023-11-23 14:58:52 +01:00
|
|
|
|
2023-11-23 14:10:48 +01:00
|
|
|
/**
|
|
|
|
* Title of the page.
|
|
|
|
*
|
|
|
|
* @var string
|
2023-11-23 15:02:36 +01:00
|
|
|
* @since 1.0.0
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
private $title;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unique identifier needed to register the settings.
|
|
|
|
*
|
|
|
|
* @var string
|
2023-11-23 15:02:36 +01:00
|
|
|
* @since 1.0.0
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
private $key;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fields to create.
|
|
|
|
*
|
|
|
|
* @var array<string, array>
|
2023-11-23 15:02:36 +01:00
|
|
|
* @since 1.0.0
|
|
|
|
* @see Option_Page::add_field()
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
private $fields = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $title Title of the page.
|
|
|
|
* @param string $key Unique identifier needed to register the settings.
|
2023-11-23 15:02:36 +01:00
|
|
|
* @since 1.0.0
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
public function __construct( $title, $key ) {
|
|
|
|
$this->title = $title;
|
|
|
|
$this->key = $key;
|
|
|
|
$this->add_hooks();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds hooks the methods to the appropriate actions.
|
2023-11-23 15:02:36 +01:00
|
|
|
*
|
|
|
|
* @since 1.0.0
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
private function add_hooks() {
|
|
|
|
add_action( 'admin_menu', array( $this, 'add_page' ) );
|
|
|
|
add_action( 'admin_init', array( $this, 'register_setting' ) );
|
2023-11-23 14:58:52 +01:00
|
|
|
add_action( 'admin_enqueue_scripts', array( $this, 'enqueues_scripts' ) );
|
2023-11-23 14:10:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a new field.
|
|
|
|
*
|
|
|
|
* @param string $type Type of the field.
|
|
|
|
* @param string $name Name of the field.
|
|
|
|
* @param array $options Additional options for the field. Can include label and placeholder.
|
2023-11-23 14:58:52 +01:00
|
|
|
* If the placeholder contains a reserved word (e.g., "image", "avatar" or "icon"),
|
|
|
|
* a double-click will trigger the WordPress media library to open directly.
|
|
|
|
* If the placeholder contains an indication of an image size "{size}px", the selected image will be the one closest to this size.
|
2023-11-23 15:02:36 +01:00
|
|
|
* @since 1.0.0
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
public function add_field( $type, $name, $options = array() ) {
|
|
|
|
$types = array( 'type' => $type );
|
|
|
|
$this->fields[ $name ] = array_merge( $types, $options );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a page to the WordPress admin area.
|
2023-11-23 15:02:36 +01:00
|
|
|
*
|
|
|
|
* @since 1.0.0
|
|
|
|
* @link https://developer.wordpress.org/reference/functions/add_options_page/
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
public function add_page() {
|
|
|
|
add_options_page( $this->title, $this->title, 'manage_options', $this->key, array( $this, 'render_form' ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Renders the form for the options page.
|
2023-11-23 15:02:36 +01:00
|
|
|
*
|
|
|
|
* @since 1.0.0
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
public function render_form() {
|
|
|
|
?>
|
|
|
|
<div class="wrap">
|
|
|
|
<h1><?php echo esc_html( $this->title ); ?></h1>
|
|
|
|
<form method="post" action="options.php">
|
|
|
|
<?php settings_fields( $this->key ); ?>
|
2025-08-12 07:22:28 +02:00
|
|
|
<?php
|
|
|
|
if ( ! empty( $this->sections ) ) :
|
|
|
|
foreach ( $this->sections as $section_id => $section ) :
|
|
|
|
$section_fields = array();
|
|
|
|
foreach ( $this->fields as $name => $field ) {
|
|
|
|
if ( isset( $field['section'] ) && $field['section'] === $section_id ) {
|
|
|
|
$section_fields[ $name ] = $field;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( empty( $section_fields ) ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
?>
|
|
|
|
<h2><?php echo esc_html( $section['title'] ); ?></h2>
|
|
|
|
<?php if ( ! empty( $section['description'] ) ) : ?>
|
|
|
|
<p class="description"><?php echo esc_html( $section['description'] ); ?></p>
|
|
|
|
<?php endif; ?>
|
|
|
|
<table class="form-table" role="presentation">
|
|
|
|
<tbody>
|
|
|
|
<?php foreach ( $section_fields as $name => $field ) : ?>
|
|
|
|
<tr>
|
|
|
|
<th scope="row">
|
|
|
|
<?php if ( ! empty( $field['label'] ) ) : ?>
|
|
|
|
<label for="<?php echo esc_attr( $name ); ?>"><?php echo esc_html( $field['label'] ); ?></label>
|
|
|
|
<?php endif; ?>
|
|
|
|
</th>
|
|
|
|
<td>
|
|
|
|
<?php $this->render_field_by_type( $name, $field ); ?>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<?php endforeach; ?>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
<?php
|
|
|
|
endforeach;
|
|
|
|
|
|
|
|
$unsectioned = array();
|
|
|
|
foreach ( $this->fields as $name => $field ) {
|
|
|
|
if ( empty( $field['section'] ) || ! isset( $this->sections[ $field['section'] ] ) ) {
|
|
|
|
$unsectioned[ $name ] = $field;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( ! empty( $unsectioned ) ) : ?>
|
|
|
|
<table class="form-table" role="presentation">
|
|
|
|
<tbody>
|
|
|
|
<?php foreach ( $unsectioned as $name => $field ) : ?>
|
|
|
|
<tr>
|
|
|
|
<th scope="row">
|
|
|
|
<?php if ( ! empty( $field['label'] ) ) : ?>
|
|
|
|
<label for="<?php echo esc_attr( $name ); ?>"><?php echo esc_html( $field['label'] ); ?></label>
|
|
|
|
<?php endif; ?>
|
|
|
|
</th>
|
|
|
|
<td>
|
|
|
|
<?php $this->render_field_by_type( $name, $field ); ?>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<?php endforeach; ?>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
<?php endif; ?>
|
|
|
|
<?php else : ?>
|
2023-11-23 14:10:48 +01:00
|
|
|
<table class="form-table" role="presentation">
|
|
|
|
<tbody>
|
|
|
|
<?php foreach ( $this->fields as $name => $field ) : ?>
|
2025-08-12 07:22:28 +02:00
|
|
|
<tr>
|
|
|
|
<th scope="row">
|
|
|
|
<?php if ( ! empty( $field['label'] ) ) : ?>
|
|
|
|
<label for="<?php echo esc_attr( $name ); ?>"><?php echo esc_html( $field['label'] ); ?></label>
|
|
|
|
<?php endif; ?>
|
|
|
|
</th>
|
|
|
|
<td>
|
|
|
|
<?php $this->render_field_by_type( $name, $field ); ?>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<?php endforeach; ?>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
<?php endif; ?>
|
2023-11-23 14:10:48 +01:00
|
|
|
<?php submit_button(); ?>
|
|
|
|
</form>
|
|
|
|
</div>
|
2024-07-30 15:18:19 +02:00
|
|
|
<?php
|
|
|
|
}
|
|
|
|
|
2025-08-12 07:22:28 +02:00
|
|
|
/**
|
|
|
|
* Renders a field by its declared type.
|
|
|
|
*
|
|
|
|
* @param string $name Field name.
|
|
|
|
* @param array $field Field configuration.
|
|
|
|
* @since 1.3.0
|
|
|
|
*/
|
|
|
|
private function render_field_by_type( $name, $field ) {
|
|
|
|
switch ( $field['type'] ) {
|
|
|
|
case 'textarea':
|
|
|
|
$this->render_textarea_field( $name, $field );
|
|
|
|
break;
|
|
|
|
case 'select':
|
|
|
|
$this->render_select_field( $name, $field );
|
|
|
|
break;
|
|
|
|
case 'checkbox':
|
|
|
|
$this->render_checkbox_field( $name );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
$this->render_input_field( $name, $field );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-30 15:27:29 +02:00
|
|
|
/**
|
|
|
|
* Renders the textarea field.
|
|
|
|
*
|
|
|
|
* @param string $name Name of the field.
|
|
|
|
* @param array $field Field to render an input for.
|
|
|
|
* @since 1.2.0
|
|
|
|
*/
|
|
|
|
private function render_textarea_field( $name, $field ) {
|
|
|
|
?>
|
|
|
|
<textarea
|
|
|
|
id="<?php echo esc_attr( $name ); ?>"
|
|
|
|
class="regular-text"
|
|
|
|
name="<?php echo esc_attr( $name ); ?>"
|
|
|
|
placeholder="<?php echo esc_attr( $field['placeholder'] ?? '' ); ?>"
|
2025-06-30 08:04:09 +02:00
|
|
|
rows="<?php echo esc_attr( $field['rows'] ?? '10' ); ?>"
|
2024-07-30 15:27:29 +02:00
|
|
|
><?php echo esc_textarea( get_option( $name ) ); ?></textarea>
|
|
|
|
<?php
|
|
|
|
}
|
|
|
|
|
2024-07-30 15:24:15 +02:00
|
|
|
/**
|
|
|
|
* Renders the select field.
|
|
|
|
*
|
|
|
|
* @param string $name Name of the field.
|
|
|
|
* @param array $field Field to render an input for.
|
|
|
|
* @since 1.1.0
|
|
|
|
*/
|
|
|
|
private function render_select_field( $name, $field ) {
|
|
|
|
$current_value = get_option( $name );
|
|
|
|
?>
|
|
|
|
<select
|
|
|
|
id="<?php echo esc_attr( $name ); ?>"
|
|
|
|
class="regular-text"
|
|
|
|
name="<?php echo esc_attr( $name ); ?>"
|
|
|
|
>
|
|
|
|
<?php foreach ( $field['options'] as $option ) : ?>
|
|
|
|
<option value="<?php echo esc_attr( $option ); ?>" <?php selected( $current_value, $option ); ?>>
|
|
|
|
<?php echo esc_html( $option ); ?>
|
|
|
|
</option>
|
|
|
|
<?php endforeach; ?>
|
|
|
|
</select>
|
|
|
|
<?php
|
|
|
|
}
|
|
|
|
|
2024-07-30 15:18:19 +02:00
|
|
|
/**
|
|
|
|
* Renders the checkbox field.
|
|
|
|
*
|
|
|
|
* @param string $name Name of the field.
|
|
|
|
* @since 1.0.1
|
|
|
|
*/
|
|
|
|
private function render_checkbox_field( $name ) {
|
|
|
|
?>
|
|
|
|
<input
|
|
|
|
type="checkbox"
|
|
|
|
id="<?php echo esc_attr( $name ); ?>"
|
|
|
|
name="<?php echo esc_attr( $name ); ?>"
|
|
|
|
value="1"
|
|
|
|
<?php checked( 1, get_option( $name ), true ); ?>
|
|
|
|
>
|
|
|
|
<?php
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Renders the input field.
|
|
|
|
*
|
|
|
|
* @param string $name Name of the field.
|
|
|
|
* @param array $field Field to render an input for.
|
|
|
|
* @since 1.0.1
|
|
|
|
*/
|
|
|
|
private function render_input_field( $name, $field ) {
|
|
|
|
?>
|
|
|
|
<input
|
|
|
|
type="<?php echo esc_attr( $field['type'] ?? 'text' ); ?>"
|
|
|
|
id="<?php echo esc_attr( $name ); ?>"
|
|
|
|
class="regular-text"
|
|
|
|
name="<?php echo esc_attr( $name ); ?>"
|
|
|
|
value="<?php echo esc_attr( get_option( $name ) ); ?>"
|
|
|
|
placeholder="<?php echo esc_attr( $field['placeholder'] ?? '' ); ?>"
|
|
|
|
>
|
2023-11-23 14:10:48 +01:00
|
|
|
<?php
|
|
|
|
}
|
|
|
|
|
2023-11-23 14:58:52 +01:00
|
|
|
/**
|
|
|
|
* Enqueues the necessary scripts.
|
2023-11-23 15:02:36 +01:00
|
|
|
*
|
|
|
|
* @since 1.0.0
|
2023-11-23 14:58:52 +01:00
|
|
|
*/
|
|
|
|
public function enqueues_scripts() {
|
|
|
|
wp_enqueue_media();
|
|
|
|
|
|
|
|
if ( ! wp_script_is( 'field-media', 'registered' ) ) {
|
2025-08-12 07:29:03 +02:00
|
|
|
wp_enqueue_script( 'field-media', get_template_directory_uri() . self::ASSETS_PATH . '/js/field-media.js', array(), null, true );
|
2023-11-23 14:58:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-23 14:10:48 +01:00
|
|
|
/**
|
|
|
|
* Registers the settings.
|
2023-11-23 15:02:36 +01:00
|
|
|
*
|
|
|
|
* @since 1.0.0
|
|
|
|
* @link https://developer.wordpress.org/reference/functions/register_setting/
|
2023-11-23 14:10:48 +01:00
|
|
|
*/
|
|
|
|
public function register_setting() {
|
|
|
|
foreach ( $this->fields as $name => $field ) {
|
|
|
|
register_setting( $this->key, $name, array(
|
|
|
|
'sanitize_callback' => function ( $input ) use ( $name ) {
|
|
|
|
if ( empty( $input ) ) {
|
|
|
|
delete_option( $name );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return $input;
|
|
|
|
}
|
|
|
|
) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|