Preskoči na sadržaj

Kako napraviti WordPress settings stranicu u adminu (Settings API)

Settings API je “core” način da dodaš polja u adminu i da WordPress automatski odradi snimanje opcija kad je sve pravilno registrovano.


Šta pravimo

Napravit ćemo mini “agency” plugin koji dodaje admin stranicu u Settings meniju i čuva opcije (npr. telefon, email, URL, boja brenda i toggle za “maintenance banner”).​
Sve ide preko Settings API: register_setting(), add_settings_section(), add_settings_field() i render callback funkcija.​

Struktura plugina

Kreiraj folder: wp-content/plugins/agency-settings/ i fajl agency-settings.php, pa ubaci ovaj kod (kompletan, radi odmah).​

<?php
/**
* Plugin Name: Agency Settings (Tutorial)
* Description: Primjer Settings API stranice za web design agenciju.
* Version: 1.0.0
* Author: Tvoja agencija
*/

if ( ! defined('ABSPATH') ) exit;

final class Agency_Settings_Tutorial {
const OPTION_KEY = 'agency_settings_tutorial';

public static function init(): void {
add_action('admin_menu', [__CLASS__, 'add_menu']);
add_action('admin_init', [__CLASS__, 'register_settings']);
}

public static function add_menu(): void {
add_options_page(
'Agency Settings',
'Agency Settings',
'manage_options',
'agency-settings-tutorial',
[__CLASS__, 'render_page']
);
}

public static function register_settings(): void {
// 1) Registruj opciju (1 “option” kao array) + sanitize callback.
register_setting(
'agency_settings_group',
self::OPTION_KEY,
[
'type' => 'array',
'sanitize_callback' => [__CLASS__, 'sanitize'],
'default' => [],
]
); // register_setting() je dio Settings API. [web:1]

// 2) Sekcija
add_settings_section(
'agency_main_section',
'Osnovne informacije',
[__CLASS__, 'section_intro'],
'agency-settings-tutorial'
); // add_settings_section() dodaje sekciju na stranici. [web:1]

// 3) Polja
add_settings_field(
'phone',
'Telefon',
[__CLASS__, 'field_phone'],
'agency-settings-tutorial',
'agency_main_section'
); // add_settings_field() dodaje polje u sekciju. [web:1]

add_settings_field(
'email',
'Email',
[__CLASS__, 'field_email'],
'agency-settings-tutorial',
'agency_main_section'
); [web:1]

add_settings_field(
'website',
'Website URL',
[__CLASS__, 'field_website'],
'agency-settings-tutorial',
'agency_main_section'
); [web:1]

add_settings_field(
'brand_color',
'Brand boja (hex)',
[__CLASS__, 'field_brand_color'],
'agency-settings-tutorial',
'agency_main_section'
); [web:1]

add_settings_field(
'show_banner',
'Prikaži banner',
[__CLASS__, 'field_show_banner'],
'agency-settings-tutorial',
'agency_main_section'
); [web:1]
}

public static function section_intro(): void {
echo '<p>Ovdje podešavaš podatke koje tema/plugin može koristiti globalno (footer, header, CTA, banner...).</p>';
}

private static function get_option(): array {
$opt = get_option(self::OPTION_KEY, []);
return is_array($opt) ? $opt : [];
}

public static function sanitize($input): array {
// Sanitizacija treba biti na “save”, a esc_* na “output”. [web:19]
$input = is_array($input) ? $input : [];

$out = [];

$out['phone'] = isset($input['phone'])
? sanitize_text_field( wp_unslash($input['phone']) )
: '';

$out['email'] = isset($input['email'])
? sanitize_email( wp_unslash($input['email']) )
: '';

$out['website'] = isset($input['website'])
? esc_url_raw( wp_unslash($input['website']) )
: ''; // esc_url_raw je tipično za storage URL-a. [web:10]

$out['brand_color'] = isset($input['brand_color'])
? sanitize_text_field( wp_unslash($input['brand_color']) )
: '';

// checkbox: ako nije poslan, tretiraj kao 0
$out['show_banner'] = ! empty($input['show_banner']) ? 1 : 0;

// Minimalna validacija hex boje (opcionalno strože)
if ( $out['brand_color'] !== '' && ! preg_match('/^#([0-9a-fA-F]{3}){1,2}$/', $out['brand_color']) ) {
add_settings_error(self::OPTION_KEY, 'brand_color_invalid', 'Brand boja mora biti npr. #0ea5e9');
$out['brand_color'] = '';
}

return $out;
}

public static function render_page(): void {
if ( ! current_user_can('manage_options') ) return;

echo '<div class="wrap">';
echo '<h1>Agency Settings</h1>';

echo '<form method="post" action="options.php">';
// options.php + Settings API automatski hendla snimanje registrovanih opcija. [web:1]
settings_fields('agency_settings_group'); // nonce + hidden fields [web:1]
do_settings_sections('agency-settings-tutorial'); // render sekcija/polja [web:1]
submit_button('Sačuvaj');
echo '</form>';

echo '</div>';
}

private static function field_base(string $key, string $type = 'text', string $placeholder = ''): void {
$opt = self::get_option();
$val = $opt[$key] ?? '';
$name = self::OPTION_KEY . '[' . $key . ']';

printf(
'<input type="%s" name="%s" value="%s" class="regular-text" placeholder="%s" />',
esc_attr($type),
esc_attr($name),
esc_attr($val),
esc_attr($placeholder)
); // esc_attr je za siguran output u HTML atribut. [web:19]
}

public static function field_phone(): void {
self::field_base('phone', 'text', '+387 61 123 456');
}

public static function field_email(): void {
self::field_base('email', 'email', 'info@domena.ba');
}

public static function field_website(): void {
self::field_base('website', 'url', 'https://domena.ba');
}

public static function field_brand_color(): void {
self::field_base('brand_color', 'text', '#0ea5e9');
echo '<p class="description">Koristi se za inline CSS varijablu.</p>';
}

public static function field_show_banner(): void {
$opt = self::get_option();
$checked = ! empty($opt['show_banner']) ? 'checked' : '';
$name = self::OPTION_KEY . '[show_banner]';

printf(
'<label><input type="checkbox" name="%s" value="1" %s /> Uključi globalni banner</label>',
esc_attr($name),
esc_attr($checked)
);
}
}

Agency_Settings_Tutorial::init();

Kako koristiti opcije u temi

Kad su opcije snimljene, možeš ih čitati bilo gdje (tema, plugin, shortcode) preko get_option(), a na outputu obavezno radi escaping (npr. esc_html, esc_url, esc_attr).​
Primjer: dodaj u functions.php (ili u plugin) mali banner i CSS varijablu boje:

add_action('wp_head', function () {
$opt = get_option('agency_settings_tutorial', []);
$color = isset($opt['brand_color']) ? $opt['brand_color'] : '';

if ($color) {
printf("<style>:root{--agency-brand:%s;}</style>\n", esc_html($color));
}
});

add_action('wp_footer', function () {
$opt = get_option('agency_settings_tutorial', []);
$show = ! empty($opt['show_banner']);

if (! $show) return;

$phone = isset($opt['phone']) ? $opt['phone'] : '';
echo '<div style="padding:12px;background:var(--agency-brand,#111);color:#fff">';
echo 'Pozovi nas: ' . esc_html($phone);
echo '</div>';
});

Bonus: kada ne koristiti Settings API

Ako ti treba custom forma koja ne ide na options.php (npr. “Test SMTP” dugme, import/export, generisanje CSS fajla), tada praviš vlastiti POST handler i štitiš ga nonce-om (wp_nonce_field() + check_admin_referer()).​
check_admin_referer() verifikuje nonce (namjeru zahtjeva), ali i dalje trebaš provjeriti capability (npr. current_user_can).​