Очередной блог фрилансера

коротко и полезно о веб-разработке

Menu Close

WordPress. Создаем удобную панель настроек

Сегодня, мы подробно рассмотрим процесс создания страницы настроек для темы WordPress, на примере замечательного фреймворка WooFramework.

Затем, мы немного усложним задачу, используя возможности jQuery, немного улучшим функциональность страницы.

WordPress – на сегодняшний день является наиболее популярной системой управления контентом (CMS). Многие разработчики выбирают WordPress в качестве CMS, независимо от типа проекта.

Этой системой очень просто пользоваться, но вы можете сделать ее еще проще, включив дополнительные панели управления для пользователей. Вместо того, чтобы открывать файлы PHP-шаблонов и манипулировать с кодом, пользователи могут использовать обычную страницу настроек в панели управления, и с ее помощью управлять вашей WordPress-темой.

Например, если ваша тема имеет красную, синюю и зеленую цветовые схемы, каждой из которых соответствует определенный CSS-файл, было бы гораздо проще, если бы пользователь мог выбирать нужный цвет из выпадающего списка. Поэтому сегодня, вы познакомитесь с процессом создания и совершенствования дополнительной страницы настроек для панели администрирования WordPress.

Шаг 1

Прежде чем мы приступим к созданию панели управления, нам понадобится тема. Поэтому загрузите архив, с исходными файлами. Вы увидите слегка измененную классическую тему WordPress. Скопируйте папку “nettuts” (так будет называться наша тема) в папку wp-content/themes. Внутри папки должны быть следующие файлы:

  • functions.php (пустой)
  • index.php
  • comments.php
  • footer.php
  • header.php
  • rtl.php
  • sidebar.php
  • style.css
  • screenshot.png
  • папка с картинками, содержащая два файла

Большая часть нашего кода, будет расположена в файле functions.php.

Тема опционально может использовать функциональный файл, расположенный внутри папки с темой, с именем functions.php. Этот файл действует так же как плагин, и если он входит в состав вашей темы, то он автоматически загружается во время инициализации WordPress (как внешних страниц так и панели администрирования).

Этот файл предполагается использовать для:

  • описания функций, используемых в различных шаблонных файлах вашей темы
  • установки дополнительных панелей управления, позволяющих пользователям настраивать цвета, стили и другие аспекты вашей темы.

(Из Кодекса WordPress)

Шаг 2

Теперь, после того как вы скачали и установили предложенную тему, зайдите на страницу “Внешний вид” – “Темы”, и активируйте нашу тему nettuts.

Теперь, нам нужно продумать html-разметку для нашей панели управления. Будем использовать вот такую структуру:

<div class="wrap rm_wrap">
	<div class="rm_opts">
		<form method="post">
			<div class="rm_section">
				<div class="rm_title>
					<h3>Title</h3>
					<submit button>
				</div>
				<div class="rm_input rm_<select/textarea/text etc>">
					<input area>
					<description>
				</div>
			</div>

		/*Выводим инпуты нужное количество раз (соответствующее количеству настроек)*/
		/* используем <div class="rm_section"> для каждой секции настроек */
		</form>
	</div>
</div>

Позвольте мне все вам все здесь объяснить. Группы настроек будут заключены в блок с классом “rm_wrap”, а затем в блок с классом “rp_opts”. Затем, внутри этих блоков, мы открываем тег form, внутри которой будут размещены все необходимые инпуты. Каждая секция настроек (Основные настройки, Настройки домашней страницы, Настройки блога и т.д.) будет расположена в отдельном блоке с именем класса “rm_section”. В этом блоке будет расположено название (для секции настроек) и несколько блоков с инпутами. Используя специальные классы для блоков, типа <div class=”rm_input rm_select”>, мы можем назначить стили выпадающим спискам, текстовым а также многострочным полям.

Наиболее важной частью всего этого является то, что нам не придется создавать весь этот код вручную – мы будем использовать возможности PHP, везде где это возможно. Нет смысла составлять код вручную, когда в нашем распоряжении есть циклы.

Шаг 3

Откройте файл functions.php своим любимым редактором кода (я использую NotePad++), и вставьте следующий код:

<?php

	$themename = "NetTuts";
	$shortname = "nt";

Это две PHP-переменные, содержащие имя вашей темы (в нашем случае это Nettuts), и псевдоним, который вы укажете (в нашем примере это nt). Псевдоним используется в качестве префикса к именам всех настроек темы, и как правило является уникальным для каждой темы.

Далее, мы создадим пару строчек кода, для автоматического генерирования списка wordpress-рубрик, вместо того, чтобы заставлять пользователя вручную указывать их ID. Вставьте следующий код, сразу же после, предыдущего:

$categories = get_categories('hide_empty=0&order_by=name');
		$wp_cats = array();

    foreach ($categories as $category_list){
        $wp_cats[$category_list -> cat_ID] = $category_list -> cat_name;
    }

array_unshift($wp_cats, "Выберите рубрику");

Этот фрагмент кода использует встроенную wordpress-функцию get_categories, для получения всех рубрик, а затем, с помощью цикла foreach, сохранения их в переменной $wp_cats. Затем к массиву добавляется опция “выберите рубрику”.

Шаг 4

Теперь пришло время создать список настроек для нашей темы. Вставьте следующий код в файл functions.php:

$options = array(

        array( "name" => "Настройки",
                "type" => "title" ),

        array ( "name" => "Основные настройки",
                "type" => "section" ),
        array ( "type" => "open"),

        array ( "name" => "Цветовая схема",
                "desc" => "Выберите цветовую схему темы",
                "id" => $shortname . "_color_scheme",
                "type" => "select",
                "options" => array ("синяя", "красная", "зеленая"),
                "std" => "blue" ),

        array ( "name" => "URL Логотипа",
                "desc" => "Введите ссылку к картинке логотипа",
                "id" => $shortname . "_logo",
                "type" => "text",
                "std" => "" ),

        array ( "name" => "Пользовательский CSS",
                "desc" => "Хотите использовать свой CSS-код? Вставьте его в это поле",
                "id" => $shortname . "_custom_css",
                "type" => "textarea",
                "std" => "" ),
        
        array ( "type" => "close"),

        array ( "name" => "Домашняя страница",
                "type" => "section" ),

        array ("type" => "open"),

        array ( "name" => "Картинка в шапке, на главной странице",
                "desc" => "Введите URL картинки, которая будет использоваться в шапке",
                "id" => $shortname ."_header_img",
                "type" => "text",
                "std" => ""),

         array ( "name" => "Рубрика домашней страницы",
                "desc" => "Выберите рубрику, в которую будут публиковатся записи",
                "id" => $shortname ."_feat_cat",
                "type" => "select",
                "options" => $wp_cats,
                "std" => "Выберите рубрику"),
        
        array ( "type" => "close"),

        array ( "name" => "Подвал",
                "type" => "section"),

        array ( "type" => "open"),

        array(  "name" => "Текст копирайта",
                "desc" => "Введите текст, который будет размещен в правой части подвала. Можно использовать HTML",
                "id" => $shortname."_footer_text",
                "type" => "text",
                "std" => ""),

        array(  "name" => "Код Google Analytics",
                "desc" => "Здесь вы можете разместить код Google Analytics, или любой другой счетчик",
                "id" => $shortname."_ga_code",
                "type" => "textarea",
                "std" => ""),

        array( "name" => "Favicon",
                "desc" => "Favicon - это пиксельная иконка, которая представляет ваш сайт. Вставьте URL к картинке с расширением .ico",
                "id" => $shortname."_favicon",
                "type" => "text",
                "std" => get_bloginfo('url') ."/favicon.ico"),

        array(  "name" => "Feedburner URL",
                "desc" => "Feedburner - это сервис Google, управляющий RSS-потоками. Paste your Feedburner URL here to let readers see it in your website",
                "id" => $shortname."_feedburner",
                "type" => "text",
                "std" => get_bloginfo('rss2_url')),

        array( "type" => "close")

    );

Это был довольно большой фрагмент кода, заслуживающий небольшого разъяснения. Итак:

  • PHP-переменная $options хранит весь список настроек для нашей темы.
  • Список настроек состоит из нескольких массивов, каждый из которых содержит ключ “type”, для определения типа настройки и способа ее отображения.
  • Наш список настроек начинается с массива “type” => “title” – который будет использоваться для отображения имени темы и названия в заголовке страницы.
  • Каждый раздел (Основные настройки, Домашняя страница, Подвал) имеет отдельный список настроек.
  • Мы начинаем новую секцию, закрывая любую из предыдущих секций, и объявления новой секции с помощью массива array(“name” => “Подвал”, “type” => “section”).
  • Каждая опция может содержать следующие настройки:
    name: Имя текстового поля.
    desc: Короткое описание поля, для пользователя.
    id:
    id поля, с префиксом из псевдонима. Оно будет использоваться как для записи настройки, так и для доступа к ней.
    type: тип input — text, select или textarea
    options: используется для объявления массива настроек для поля выпадающего списка.
    std: значение поля по умолчанию, используется если никаких других значений не указано.

Шаг 5

Попробуйте зайти в панель управления WordPress. Вы нигде не найдете указанных нами настроек, как же нам отобразить их? Добавляем следующий код в файл functions.php:

function mytheme_add_admin(){
        
        global $themename, $shortname, $options;
		
        if($_GET['page'] == basename(__FILE__) ){
            
            if( 'saved' == $_REQUEST['action']){
                foreach ($options as $value){
                    update_option($value['id'], $_REQUEST[$value['id']]);
                }

                foreach ($options as $value){
                    if( isset ($_REQUEST[$value['id']]) ){
                        update_option($value['id'], $_REQUEST[$value['id']] );
                    }else{
                        delete_option($value['id']);
                    }
                }
                header("Location: admin.php?page=functions.php&saved=true");
                die;
            }
        }

        else if('reset' == $_REQUEST['action']){
            foreach($options as $value){
                delete_option($value['id']);
            }

            header("Location: admin.php&page=functions.php&reset=true");

            die;
        }

         add_menu_page($themename, $themename, 'administrator', basename(__FILE__), 'mytheme_admin');
    }

    function mytheme_add_init() {
 
}

Эта функция используется как для обновления самих настроек, так и для добавления страницы в панели управления. Если настройки были сохранены (определяется с помощью скрытой переменной save), то все настройки обновляются указанными значениями. Если же, настройки были сброшены (определяется с помощью другой скрытой переменной reset), то все настройки удаляются.

Последняя строка функции, добавляет страницу меню – параметры по порядку: имя и название, уровень пользовательских прав для просмотра страницы, страница сохранения и функция, использующаяся для отображения/сохранения настроек (в нашем примере называется mytheme_admin).

Заметили, что функция mytheme_add_init пустая? Пусть пока останется такой как есть, мы вернемся к ней позже.

Шаг 6

Страница настроек в панели управления так и не появилась? Но, мы еще не дописали функцию mytheme_admim, о которой говорилось выше. Для создания этой функции нам понадобится код из шагов 6,7 и 8. Давайте начнем.

function mytheme_admin(){
        global $themename, $shortname, $options;
        $i = 0;

         if($_REQUEST['action'] == 'save')
	echo '<div id="message" class="updated fade"><p><strong> настройки темы '. $themename .' были сохранены</strong></p></div>';  

        if($_REQUEST['reset'])
            echo '<div id="message" class="updated fade"><p><strong> настройки темы '. $themename .' были сброшены</strong></p></div>';
    ?>

<div class="wrap rm_wrap">
    <h2>Настройки <?php echo $themename ?></h2>

    <div class="rm_opts">
        <form method="post">

Очень просто, не правда ли? Если настройка была сохранена, выводим подтверждающее сообщение. То же самое для сброса. Обратите внимание на класс “update fade” – WordPress автоматически выведет это сообщение в самом верху окна. Удобно, не правда ли? Идем дальше, начиная с блока “rm_wrap”

Шаг 7

Вставляем следующий код, ниже:

<?php foreach($options as $value) {
                    switch ($value['type']){
                    case "open" :
             ?>

            <?php
                    break;
                    case "close" :
            ?>

            </div>
            </div>
            <br />

            <?php
                    break;
                    case "title" :
            ?>

            <p>Для более удобного управления темой <?php echo $themename;?>, вы можете использовать меню, расположенное ниже</p>

            <?php
                    break;
                    case "text" :
            ?>

            <div class="rm_input rm_text">
                <label for="<?php echo $value['id']?>">
                    <?php echo $value['name']?>
                </label>

                <input name="<?php echo $value['id']?>" id="<?php echo $value['id']?>" type="<?php echo $value['type']?>"
                       value="<?php if (get_settings($value['id']) != ""){ echo stripslashes(get_settings($value['id'])); } else {echo $value["std"];} ?>" />

                <small><?php echo $value['desc']; ?></small>
                <div class="clearfix"></div>
            </div>

             <?php
                    break;
                    case "textarea" :
            ?>

            <div class="rm_input rm_textarea">
                <label for="<?php echo $value['id']?>">
                    <?php echo $value['name']?>
                </label>

                <textarea name="<?php echo $value['id']?>" type="<?php echo $value['type']?>" >
                    <?php if (get_settings($value['id']) != ""){
                                echo stripslashes(get_settings($value['id']));
                          }else {
                                echo $value["std"];
                          }?>
                </textarea>

                <small><?php echo $value['desc']; ?></small>
                <div class="clearfix"></div>
            </div>

            <?php
                    break;

Здесь используется php-цикл foreach, каждый тип настроек определяется индивидуально для каждого случая. Для этого мы будем использовать оператор switch. Переменная в операторе switch – это текущий тип параметра, case – ожидаемый тип параметра. Вы, наверное, обратили внимание на выражение “break”, после каждого case? Это выражение используется для предотвращения неправильной обработки условия. Когда значение case соответствует переменной, все последующие case также будут выполнены. То есть, если у нас определен case3, то кроме него, также будут выполняться case4, case5 и т.д. Но нам этого не нужно, поэтому мы используем break, для прекращения работы оператора switch.

Если текущее значение параметра “open” – ничего не происходит. Если текущее значение “close”, ставятся два закрывающих блока. Значение параметра “title” используется только один раз – во вступительном тексте перед настройками темы. Для каждого типа “text” (input type=”text”), “select” (выпадающий список) и “textarea” (название говорит само за себя) – отображается соответствующий input. Обратите внимание на блок <div class=”clearfix”> – он используется для чистки флоатов, которые мы будем использовать далее.

Шаг 8

Мы приближаемся к концу этой довольно большой функции. Вставьте следующий код:

case "select" :
            ?>

            <div class="rm_input rm_select">
                 <label for="<?php echo $value['id']?>">
                    <?php echo $value['name']?>
                </label>

                <select name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>">
                    <?php foreach ($value['options'] as $option) : ?>
                    <option <?php if(get_settings($value['id']) == $option){ echo "selected=selected";} ?>>
                        <?php echo $option; ?>
                    </option>
                    <?php endforeach; ?>
                </select>

                 <small><?php echo $value['desc']; ?></small>
                 <div class="clearfix"></div>
            </div>

             <?php
                    break;
                    case "checkbox" :
            ?>

            <div class="rm_input rm_checkbox">
                <label for="<?php echo $value['id']?>">
                    <?php echo $value['name']?>
                </label>

                <?php if(get_options($value['id'])){
                        $checked = "checked=\"checked\"";
                    }else{
                        $checked = "";
                    }
                ?>

                <input type="checkbox" name="<?php echo $value['id']?>" id="<?php echo $value['id']?>" value="true" <?php echo $checked; ?> />

                <small><?php echo $value['desc']; ?></small>
                <div class="clearfix"></div>
            </div>

            <?php
                    break;
                    case "section" :
                    $i++;
            ?>

            <div class="rm_section">
                <div class="rm_title">
                    <h3>
                        <img src="<?php bloginfo('template_directory')?>/functions/images/trans.gif" class="inactive" alt=""/>
                        <?php echo $value['name']; ?>
                    </h3>
					
					 <span class="submit">
                            <input name="save<?php echo $i; ?>" type="submit" value="Сохранить" />
                  	 </span>
                    <div class="clearfix"></div>
                </div>

                <div class="rm_options">
            <?php
                    break;
                    }
                }
            ?>
            <input type="hidden" name="action" value="save" />
        </form>

        <form method="post">
            <p class="submit">
                <input name="reset" type="submit" value="Сброс" />
                <input name="action" type="hidden" value="reset" />
            </p>
        </form>

        <div style="font-size:9px; margin-bottom:10px;">
            Иконки: <a href="http://www.woothemes.com/2009/09/woofunction/">WooFunction</a>
        </div>
</div>

  <?php  }

Для типа настройки “section”, мы используем переменную-счетчик $i. Это позволяет отслеживать номер секций и соединять его с именем кнопки отправки данных, получая таким образом уникальное имя для каждой кнопки. Кроме того, в конец секции добавляется форма, для сброса всех настроек. Картинка будет использована для дальнейшей jQuery-фикации. Это последний фрагмент кода, который приведет наши функции в действие:


add_action('admin_init', 'mytheme_add_init');
add_action('admin_menu', 'mytheme_add_admin');
 

Этот код добавляет дополнительную страницу в панели управления WordPress.

Шаг 9

Отлично, теперь у нас есть собственная страница управления, с отдельным пунктом меню. Однако, зайдя на эту страничку, мы видим, что не все так хорошо как нам бы хотелось. Но не беда, у нас есть отличный помощник – CSS! Создаем новую папку “functions”, внутри папки nettuts. Внутри этой папки, создаем новый файл – functions.css, и вставляем в него следующий код:

.rm_wrap{
	width:740px;
}
.rm_section{
	border:1px solid #ddd;
	border-bottom:0;
	background:#f9f9f9;
}
.rm_opts label{
	font-size:12px;
	font-weight:700;
	width:200px;
	display:block;
	float:left;
}
.rm_input {
	padding:30px 10px;
	border-bottom:1px solid #ddd;
	border-top:1px solid #fff;
}
.rm_opts small{
	display:block;
	float:right;
	width:200px;
	color:#999;
}
.rm_opts input[type="text"], .rm_opts select{
	width:280px;
	font-size:12px;
	padding:4px;
	color:#333;
	line-height:1em;
	background:#f3f3f3;
}
.rm_input input:focus, .rm_input textarea:focus{
		background:#fff;
}
.rm_input textarea{
	width:280px;
	height:175px;
	font-size:12px;
	padding:4px;
	color:#333;
	line-height:1.5em;
	background:#f3f3f3;
}
.rm_title h3 {
	cursor:pointer;
	font-size:1em;
	text-transform: uppercase;
	margin:0;
	font-weight:bold;
	color:#232323;
	float:left;
	width:80%;
	padding:14px 4px;
}
.rm_title{
	cursor:pointer;
	border-bottom:1px solid #ddd;
	background:#eee;
	padding:0;
}
.rm_title h3 img.inactive{
	margin:-8px 10px 0 2px;
	width:32px;
	height:32px;
	background:url('images/pointer.png') no-repeat 0 0;
	float:left;
	-moz-border-radius:6px;
	border:1px solid #ccc;
}
.rm_title h3 img.active{
	margin:-8px 10px 0 2px;
	width:32px;
	height:32px;
	background:url('images/pointer.png') no-repeat  0 -32px;
	float:left;
	-moz-border-radius:6px;
	-webkit-border-radius:6px;
	border:1px solid #ccc;
}
.rm_title h3:hover img{
	border:1px solid #999;
}
.rm_title span.submit{
	display:block;
	float:right;
	margin:0;
	padding:0;
	width:15%;
	padding:14px 0;
}
.clearfix{
	clear:both;
}
.rm_table th, .rm_table td{
	border:1px solid #bbb;
	padding:10px;
	text-align:center;
}
.rm_table th, .rm_table td.feature{
	border-color:#888;
	}

Думаю, этот код не требует каких-либо разъяснений, все предельно просто и понятно. Вы, конечно, можете изменять его по своему вкусу.

Шаг 10

Теперь, когда у нас есть готовый CSS-файл, как же подключить его к странице, если у нас нет прямого доступа к разделу документа <head>? Помните, мы создали пустую функцию mytheme_add_init()? Вон она-то как раз нам и поможет. Измените ее следующим образом:

function mytheme_add_init() {
       $file_dir = get_bloginfo('template_directory');
       wp_enqueue_style("functions", $file_dir."/functions/functions.css", false, "1.0", "all");
}

Этот код подключит файл functions.css в раздел документа <head>. Расположение файла определяется папкой с шаблоном.

Шаг 11

Взгляните на нашу страницу. Она выглядит вполне хорошо, осталось лишь добавить функциональность иконкам плюса, в заголовках секции. Для этого будем использовать jQuery. Создайте новый файл rm_script.js внутри папки nettuts/functions/folder. Вставьте следующий код:

jQuery(document).ready(function(){
		jQuery('.rm_options').slideUp();

		jQuery('.rm_section h3').click(function(){
			if(jQuery(this).parent().next('.rm_options').css('display')==='none')
				{	jQuery(this).removeClass('inactive').addClass('active').children('img').removeClass('inactive').addClass('active');

				}
			else
				{	jQuery(this).removeClass('active').addClass('inactive').children('img').removeClass('active').addClass('inactive');
				}

			jQuery(this).parent().next('.rm_options').slideToggle('slow');
		});
});

Что же делает этот код? После того как DOM загружен, все блоки с классом “rm_options” сворачиваются. Затем, при клике на иконке плюса, удаляется класс “inactive”, и добавляется класс “active”, который заменяет иконку на знак минус. При повторном нажатии этой иконки, происходит обратный процесс. Для сворачивания/разворачивания блоков используется довольно простая функция jQuery slideToggle. Чтобы подключить этот скрипт к странице, мы будем использовать уже знакомую нам функцию mytheme_add_init(), измените ее следующим образом:

function mytheme_add_init() {
       $file_dir = get_bloginfo('template_directory');
       wp_enqueue_style("functions", $file_dir."/functions/style.css", false, "1.0", "all");
       wp_enqueue_script("rm_script", $file_dir."/functions/script.js", false, "1.0");  
}

После этого, скрипт должен работать. Проверьте, как это выглядит на странице:

Шаг 12

Теперь, после того как наша страница настроек полностью готова, осталось немного рассказать об использовании самих настроек. Код, позволяющий использовать параметры, выглядит следующим образом:

$var = get_option('nt_colur_scheme');

С его помощью, мы сможем реализовать смену цветовой схемы сайта. Это довольно просто:

/* Изменяем CSS-файл, в зависимости от выбранного цвета */
<link rel="stylesheet" type="text/css"  href="<?php bloginfo('template_directory'); ?>/<?php echo get_option('nt_color_scheme'); ?>.css" /> 

/*Выводим текст в подвале, можно использовать HTML-тэги */
<p><?php echo stripslashes(get_option('bl_footer_text')); ?></p>

Область применения ограничивается только вашим воображением.

Скачать архив с приведенным примером.

Перевод статьи “How to Create a Better WordPress Options Panel”, автор Rohan Mehta