Một trong những yêu cầu của các theme WordPress hiện nay để nó thân thiện hơn với người sử dụng đó là có tích hợp một khu vực thiết lập và tùy chỉnh theme (gọi là Theme Options). Chẳng hạn bạn có thể cho phép người dùng tự đổi logo, màu chữ này nọ,…trong theme thông qua tính năng Theme Options này.
Để làm được Theme Options, bạn có thể sử dụng chức năng Settings API có sẵn trong WordPress hoặc sử dụng một framework/script riêng cho việc này. Trong khuôn khổ bài này, mình sẽ hướng dẫn bạn tích hợp Theme Options vào theme của serie Lập trình theme WordPress thông qua Redux Framework – một framework rất nổi tiếng trong việc tạo Theme Options cho WordPress, rất chuyên nghiệp và miễn phí.
Bước 1. Tích hợp TGM Plugin Activation
TGM Plugin Activation mình đã từng giới thiệu tại đây, nó là một script PHP giúp bạn thêm tính năng bắt buộc người dùng phải cài đặt các plugin yêu cầu khi kích hoạt theme. Sở dĩ chúng ta phải dùng TGM Plugin Activation ở đây đó là Redux Framework bây giờ hoạt động như một plugin WordPress, điều này sẽ giúp người dùng luôn luôn sử dụng phiên bản Redux Framework mà không cần phải chờ đợi các đợt cập nhật từ bạn.
Hãy tải TGM Plugin Activation tại đây, giải nén ra và copy file class-tgm-plugin-activation.php vào thư mục /themes/thachpham/core. Sau đó mở file init.php trong cùng thư mục lên và thêm đoạn này vào:
<?php
/* Plugin Activation */
require_once dirname( __FILE__ ) . ‘/class-tgm-plugin-activation.php’;
Sau đó tạo thêm một file tên là plugins.php trong cùng thư mục core và thêm đoạn này vào:
<?php
function thachpham_plugin_activation() {// Khai bao plugin can cai dat
$plugins = array(
array(
‘name’ => ‘Redux Framework’,
‘slug’ => ‘redux-framework’,
‘required’ => true
)
);// Thiet lap TGM
$configs = array(
‘menu’ => ‘tp_plugin_install’,
‘has_notice’ => true,
‘dismissable’ => false,
‘is_automatic’ => true
);
tgmpa( $plugins, $configs );}
add_action(‘tgmpa_register’, ‘thachpham_plugin_activation’);
?>
Và chèn thêm đoạn sau vào file init.php để file plugins.php này được gọi ra.
require_once dirname( __FILE__ ) . ‘/plugins.php’;
Kết quả sau khi thêm TGM Plugin Activation:
Bạn hãy ấn nút Begin installing plugin để cài plugin Redux Framework này vào để chút nữa chúng ta sẽ làm việc.
Bước 2. Cài đặt Redux Framework
Sau khi cài plugin Redux Framework vào website thì nó sẽ hiển thị thông báo thế này trên website.
Tuy nhiên chúng ta sẽ không sử dụng cái sample config file của Redux Framework vì nó chứa rất nhiều option fields mà bạn không cần dùng tới, sẽ mất công sửa lại mà chúng ta sẽ tự tạo ra một file option riêng chứa các thiết lập riêng cần thiết.
Nếu bạn muốn tự tìm hiểu về các đoạn code của Redux Framework, hãy mở file sample-config.php trong thư mục plugins Redux Framework để xem hoặc file barebones-config.php để xem cấu trúc một file tạo theme options hoàn chỉnh từ framework này.
Bước 3. Lên kế hoạch tạo Theme Options
Trước khi tiến hành viết code tạo các tùy chọn trong Theme Options, chúng ta cần nên biết rõ sẽ tạo ra những tùy chọn nào để người dùng sử dụng. Trong khuôn khổ bài này, mình sẽ lấy ví dụ các tùy chọn cơ bản trong theme như:
- Bật/tắt chức năng sử dụng ảnh làm logo.
- Sửa/xóa ảnh làm logo.
- Thay đổi màu sắc liên kết trong theme.
- Thêm font chữ từ Google Fonts.
Bước 4. Viết code tạo tùy chọn cho Theme Options
4.1) Tạo file chứa code các tùy chọn (options.php)
Bây giờ bạn hãy vào thư mục /themes/thachpham/core/ và tạo một file mang tên options.php. Sau đó mở file init.php ra và chèn đoạn sau vào để kích hoạt file options.php để nó hoạt động:
/* Theme Options */
require_once dirname( __FILE__ ) . ‘/options.php’;
Trong options.php, chúng ta khai báo một class để chứa các options như sau:
<?php
if ( ! class_exists( ‘ThachPham_Theme_Options’ ) ) {/* class ThachPham_Theme_Options sẽ chứa toàn bộ code tạo options trong theme từ Redux Framework */
class ThachPham_Theme_Options {}
/* Kích hoạt class ThachPham_Theme_Options vào Redux Framework */
global $reduxConfig;
$reduxConfig = new ThachPham_Theme_Options();
}
Và từ bây giờ, chúng ta sẽ viết code tạo từng khu vực options và từng options vào bên trong class ThachPham_Theme_Options
.
4.2) Khai báo các đoạn code cần thiết vào class ThachPham_Theme_Options.
Tất cả các code dưới đây đều phải viết vào bên trong cặp class ThachPham_Theme_Options {}
.
Trước tiên, bạn phải khai báo lại các biến toàn cục mà Redux Framework có sử dụng để chúng ta có thể tái sử dụng lại.
/* Tái tạo các biến có trong Redux Framework */
public $args = array();
public $sections = array();
public $theme;
public $ReduxFramework;
Kế tiếp là thêm code để Redux Framework được kích hoạt.
/* Load Redux Framework */
public function __construct() {if ( ! class_exists( ‘ReduxFramework’ ) ) {
return;
}// This is needed. Bah WordPress bugs. ;)
if ( true == Redux_Helpers::isTheme( __FILE__ ) ) {
$this->initSettings();
} else {
add_action( ‘plugins_loaded’, array( $this, ‘initSettings’ ), 10 );
}}
Thêm nữa, trong class ReduxFramework nó có một số phương thức mà nếu bạn muốn sử dụng thì sẽ cần phải khai báo vào một phương thức khác tên là initSettings. Chúng ta có đoạn code khai báo các phương thức cần sử dụng như sau:
/**
Thiết lập các method muốn sử dụng
Method nào được khai báo trong này thì cũng phải được sử dụng
**/
public function initSettings() {// Set the default arguments
$this->setArguments();// Set a few help tabs so you can see how it’s done
$this->setHelpTabs();// Create the sections and fields
$this->setSections();if ( ! isset( $this->args ) ) { // No errors please
return;
}$this->ReduxFramework = new ReduxFramework( $this->sections, $this->args );
}
Nghĩa là chúng ta sẽ cần sử dụng 3 phương thức là:
setArguments
: Phương thức này sẽ thiết lập một số tùy chọn cho cái Theme Options.setHelpTabs
: Phương thức này để tạo mục hướng dẫn ngay bên trong phần hiển thị Theme Options.setSections
: Đây là phương thức quan trọng nhất, dùng để chia phân mục các tùy chọn trong Theme Options, và chúng ta cũng sẽ khai báo các field tùy chọn bên trong phương thức này.
Ok, bây giờ chúng ta sẽ code cho từng phương thức một.
4.3) Viết code cho phương thức initSettings
Như mình đã nói ở trên rằng phương thức này sẽ được dùng để khai báo một số tùy chọn chung chung cho khu vực Theme Options, chúng ta có đoạn code sau (nhớ là đặt bên trong class ThachPham_Theme_Options {}):
/**
Thiết lập cho method setAgruments
Method này sẽ chứa các thiết lập cơ bản cho trang Options Framework như tên menu chẳng hạn
**/
public function setArguments() {
$theme = wp_get_theme(); // Lưu các đối tượng trả về bởi hàm wp_get_theme() vào biến $theme để làm một số việc tùy thích.
$this->args = array(
// Các thiết lập cho trang Options
‘opt_name’ => ‘tp_options’, // Tên biến trả dữ liệu của từng options, ví dụ: tp_options
‘display_name’ => $theme->get( ‘Name’ ), // Thiết lập tên theme hiển thị trong Theme Options
‘menu_type’ => ‘menu’,
‘allow_sub_menu’ => true,
‘menu_title’ => __( ‘TP Theme Options’, ‘thachpham’ ),
‘page_title’ => __( ‘TP Theme Options’, ‘thachpham’ ),
‘dev_mode’ => false,
‘customizer’ => true,
‘menu_icon’ => ”, // Đường dẫn icon của menu option
// Chức năng Hint tạo dấu chấm hỏi ở mỗi option để hướng dẫn người dùng */
‘hints’ => array(
‘icon’ => ‘icon-question-sign’,
‘icon_position’ => ‘right’,
‘icon_color’ => ‘lightgray’,
‘icon_size’ => ‘normal’,
‘tip_style’ => array(
‘color’ => ‘light’,
‘shadow’ => true,
’rounded’ => false,
‘style’ => ”,
),
‘tip_position’ => array(
‘my’ => ‘top left’,
‘at’ => ‘bottom right’,
),
‘tip_effect’ => array(
‘show’ => array(
‘effect’ => ‘slide’,
‘duration’ => ‘500’,
‘event’ => ‘mouseover’,
),
‘hide’ => array(
‘effect’ => ‘slide’,
‘duration’ => ‘500’,
‘event’ => ‘click mouseleave’,
),
),
) // end Hints
);
Ở mỗi đoạn mình đã có viết chú thích rồi nên bạn có thể đọc bên trong đó nhé.
4.4) Viết code cho phương thức setHelpTabs:
Help Tabs là tính năng rất hữu dụng để bạn viết các đoạn hướng dẫn và người đùng có thể nhìn thấy tại nút Help nằm bên phải góc trên trong trang Theme Options:
/**
Thiết lập khu vực Help để hướng dẫn người dùng
**/
public function setHelpTabs() {// Custom page help tabs, displayed using the help API. Tabs are shown in order of definition.
$this->args[] = array(
‘id’ => ‘redux-help-tab-1’,
‘title’ => __( ‘Theme Information 1’, ‘thachpham’ ),
‘content’ => __( ‘<p>This is the tab content, HTML is allowed.</p>’, ‘thachpham’ )
);$this->args[] = array(
‘id’ => ‘redux-help-tab-2’,
‘title’ => __( ‘Theme Information 2’, ‘thachpham’ ),
‘content’ => __( ‘<p>This is the tab content, HTML is allowed.</p>’, ‘thachpham’ )
);// Set the help sidebar
$this->args = __( ‘<p>This is the sidebar content, HTML is allowed.</p>’, ‘thachpham’ );
}
4.5) Tạo khu vực tùy chọn với setSections:
Đây là phương thức quan trọng nhất, nó dùng để khai báo các khu vực tùy chọn (option section) và các tùy chọn nằm bên trong mỗi section.
Trước tiên mình có đoạn code ban đầu như sau để tạo một section trước:
/**
Thiết lập từng phần trong khu vực Theme Options
mỗi section được xem như là một phân vùng các tùy chọn
Trong mỗi section có thể sẽ chứa nhiều field
**/
public function setSections() {// Home Section
$this->sections[] = array(
‘title’ => __( ‘Header’, ‘thachpham’ ),
‘desc’ => __( ‘All of settings for header on this theme.’, ‘thachpham’ ),
‘icon’ => ‘el-icon-home’,
‘fields’ => array()
); // end section}
Ngay tại code trên, từ đoạn //Home Section
đến // end section
là một code tạo một khu vực tùy chọn, trong đó có các tham số sau:
title
: Tên của sectiondesc
: Mô tả của sectionicon
: đường dẫn hoặc tên của icon (trong bộ Elusive Icon http://elusiveicons.com/icons/).fields
: Các đoạn code tạo tùy chọn cho section này
Ngay sau khi xong đoạn code trên, bạn đã có thể vào Dashboard để xem phần Theme Options đã được hiển thị ra rồi.
Bây giờ ngay tại tham số fields
trong đoạn tạo section trên, chúng ta sẽ tạo ra hai options cho tùy chọn bật chức năng hiển thị logo là ảnh và field upload ảnh làm logo lên. Chúng ta có thêm code như sau vào tham số fields:
‘fields’ => array(
// Mỗi array là một field
array(
‘id’ => ‘logo-on’,
‘type’ => ‘switch’,
‘title’ => __( ‘Enable Image Logo’, ‘thachpham’ ),
‘compiler’ => ‘bool’, // Trả về giá trị kiểu true/false (boolean)
‘desc’ => __( ‘Do you want to use image as a logo?’, ‘thachpham’ ),
‘on’ => __( ‘Enabled’, ‘thachpham’ ),
‘off’ => __(‘Disabled’)
),array(
‘id’ => ‘logo-image’,
‘type’ => ‘media’,
‘title’ => __( ‘Logo Image’, ‘thachpham’ ),
‘desc’ => __( ‘Image that you want to use as logo’, ‘thachpham’ ),
),
)
Ở đoạn trên, rõ ràng mình có hai mảng array bên trong tham số fields
, như vậy điều này tương đương với ta có 2 options. Trong code tạo options trên, các tham số này là của từng loại field trong ReduxFramework nên tốt hơn hết bạn xem các tùy chọn của từng loại fields trong ReduxFramework tại đây.
Trong các đoạn code tạo options, bạn lưu ý nhất là tham số id, đó chính là tên của mỗi field để sau này chúng ta có thể sẽ gọi giá trị của nó ra ngoài theme theo kiểu $opt_name
. Biến $opt_name
chính là tham số opt_name
trong phương thức setArguments()
.
Sau khi đặt các đoạn code tạo option kia vào section Header mà ta đã tạo ở trên, khi vào Theme Options ta sẽ thấy như thế này:
Bây giờ để có thể mang dữ liệu ra bên ngoài, trước tiên bạn hãy vào Theme Options và thử chọn các tùy chọn bất kỳ để nó gán giá trị vào database, sau đó ấn Save Changes lại để lưu.
Như bạn biết thì trong phương thức setArgrument
ta đã sử dụng tham số opt_name để khai báo một biến để chứa các dữ liệu mảng cho mỗi option. Trong bài này thì mình đã gán cho nó với tên là tp_options
, vậy thì chúng ta phải đặt biến này thành dạng global ở file mà chúng ta muốn gọi giá trị ra như thế này:
<?php
global $tp_options;
echo ‘<pre>’;
print_r( $tp_options );
echo ‘</pre>’;
?>
Bạn có thể đặt thử đoạn trên vào đầu file header.php để chúng ta xem các giá trị trong options:
Dựa theo giá trị debug đó, chúng ta có thể lấy giá trị dựa theo tên của từng key trong mảng đó là được.
Bây giờ bạn mở file functions.php lên, tìm đến hàm thachpham_logo()
như thế này:
if (!function_exists(‘thachpham_header’)) {
function thachpham_header() { ?>
<div class="site-name">
<?php
global $tp_options;if( $tp_options == 0 ) :
?>
<?php
if ( is_home() ) {
printf( ‘<h1><a href="%1$s" title="%2$s">%3$s</a></h1>’,
get_bloginfo(‘url’),
get_bloginfo(‘description’),
get_bloginfo(‘sitename’) );
} else {
printf( ‘<p><a href="%1$s" title="%2$s">%3$s</a></p>’,
get_bloginfo(‘url’),
get_bloginfo(‘description’),
get_bloginfo(‘sitename’) );
}
?><?php
else :
?>
<img src="<?php echo $tp_options; ?>" />
<?php endif; ?>
</div>
<div class="site-description"><?php bloginfo(‘description’); ?></div><?php
}
}
Việc của chúng ta cần làm là thêm đoạn code kiểm tra cái tùy chọn bật logo bằng hình ảnh, sau đó thêm đoạn code hiển thị logo nếu cái tùy chọn Enable Logo Image đang On (giá trị là 1):
/**
@ Thiết lập hàm hiển thị logo
@ thachpham_logo()
**/
if ( ! function_exists( ‘thachpham_logo’ ) ) {
function thachpham_logo() {?>
<?php
global $tp_options;
?><?php if ( $tp_options == 1 ) : ?>
<div class="logo">
<img src="<?php echo $tp_options; ?>">
</div><?php else : ?>
<div class="logo">
<div class="site-name">
<?php if ( is_home() ) {
printf(
‘<h1><a href="%1$s" title="%2$s">%3$s</a></h1>’,
get_bloginfo( ‘url’ ),
get_bloginfo( ‘description’ ),
get_bloginfo( ‘sitename’ )
);
} else {
printf(
‘<a href="%1$s" title="%2$s">%3$s</a>’,
get_bloginfo( ‘url’ ),
get_bloginfo( ‘description’ ),
get_bloginfo( ‘sitename’ )
);
} // endif ?>
</div>
<div class="site-description"><?php bloginfo( ‘description’ ); ?></div></div>
<?php endif;
}
}
Giờ thì bạn có thể thử vào Theme Options và thiết lập bật chức năng hiển thị logo lên, đồng thời upload ảnh muốn làm logo và ta có kết quả sau khi bật:
4.6) Tiếp tục tạo thêm một section cho Theme Options:
Ở phần này, chúng ta sẽ tạo thêm một section mang tên Typography trong phần Theme Options, tại đây chúng ta sẽ cho phép người dùng thiết lập font chữ và màu chữ, màu liên kết:
Ngay tại phương thức setSections, chúng ta sẽ thêm một section mới như sau:
// Typography Section
$this->sections[] = array(
‘title’ => __( ‘Typography’, ‘thachpham’ ),
‘desc’ => __( ‘All of settings for themes typography’, ‘thachpham’ ),
‘icon’ => ‘el-icon-font’,
‘fields’ => array()
); // end section
Kết quả:
Ngay tại tham số fields
, chúng ta có một số options như sau:
‘fields’ => array(
// Main typography
array(
‘id’ => ‘typo-main’,
‘type’ => ‘typography’,
‘title’ => ‘Main Typography’,
‘output’ => array( ‘body’ ),
‘text-transform’ => true,
‘default’ => array(
‘font-size’ => ’14px’,
‘font-family’ => ‘Helvetica Neue, Arial, sans-serif’,
‘font-color’ => ‘#333333’,
),
),
)
Đồng thời, bạn phải khai báo thêm Google API Key để cái Google Font có thể làm việc được. Hãy thêm tham số này vào phương thức setArguments
:
‘google_api_key’ => ‘XXXXXXXXXXX’,
Trong đó, XXX là Google API Key của bạn, bạn hãy xem thêm hướng dẫn lấy API Key tại https://developers.google.com/fonts/docs/developer_api#Auth. Hoặc bạn có thể sử dụng tạm AIzaSyAs0iVWrG4E_1bG244-z4HRKJSkg7JVrVQ để test.
Ngay đoạn fields ở trên, mình có các tham số cơ bản trong một options, tuy nhiên các bạn nên lưu ý tham số ouput. Tham số ouput nghĩa là chúng ta sẽ khai báo vùng chọn để nó tự tạo ra CSS, ví dụ như trên mình khai báo vùng chọn body thì nó sẽ tự tạo ra CSS với kiểu body {....}
để hiển thị các giá trị.
Tham số default là chúng ta sẽ khai báo các giá trị mặc định nếu như typography không được chọn. Như vậy, bạn hãy vào file style.css, tìm đến vùng chọn body và xóa các giá trị CSS liên quan đến tham số default để nó khỏi xung đột nhé.
Kết quả sau khi tạo xong option:
Hãy thử chọn các tùy chọn mà bạn thích rồi ấn Save lại. Bây giờ khi xem source của website, bạn sẽ thấy các tùy chọn đã được tạo ra như một đoạn CSS với vùng chọn là tham số output.
Mình nhắc lại là nếu bạn tạo tùy chọn Typography cho vùng chọn nào thì hãy đảm bảo rằng bạn hãy xóa hết các đoạn CSS liên quan đến vùng chọn đó trong file style.css vì nếu nó vẫn còn thì các CSS trong file style.css sẽ được ưu tiên.
Bây giờ bạn có thể ứng dụng tạo ra thêm các tùy chọn typography dành cho các vùng chọn khác mà bạn thích rồi đấy.
Lời kết
Trong bài viết dài này, mình đã nói rất chi tiết về việc sử dụng Redux Framework để tạo theme options và cách thêm các options cơ bản. Như mình đã nói ở trên, bài viết này mình chỉ lướt qua Redux Framework nên nếu có gì bạn chưa hiểu thì xem thêm Redux Documentation để hiểu thêm framework này.
Tải toàn bộ code sau khi làm xong bài này tại đây.