Tuesday, December 29, 2015

PrestaShop 1.6.x. How to add drop down menus in “Top Horizontal Menu” module

This module allows you to build all types of horizontal navigation bars.

Adding a product category sub-menu to your navigation menu

  1. Add a new product category link to the top menu :
    1. Navigate to Modules -> Modules and look for Top horizontal menu.
    2. Click the Configure button to access the module configuration page:
      How_to_add_drop_down_menus_in_Top_Horizontal_Menu_module_1
    3. To add a new element to the frontend menu, you should select the required element on the right and click the Add button:
      How_to_add_drop_down_menus_in_Top_Horizontal_Menu_module_2
    4. Click Save to confirm adding a new menu item for the top menu.
  2. Add a new sub-category to your product category.
    1. Navigate to the Catalog -> Categories menu. To create a new sub-category, click on the Add New button from any level of categories:
      How_to_add_drop_down_menus_in_Top_Horizontal_Menu_module_3
This sub-category will be displayed as a drop-down menu button for product category automatically.

Adding a CMS pages sub-menu to your navigation menu

  1. Create a new CMS category.
    1. Navigate to Preferences -> CMS and click  Add new CMS category button:
      How_to_add_drop_down_menus_in_Top_Horizontal_Menu_module_4
    2. Fill in the choices suggested and click ‘Save’ button.
  2. Add a new CMS category to the top menu :
    1. Navigate to Modules -> Modules and look for Top horizontal menu.
    2. Click the Configure button to access the module configuration page.
    3. To add a new element to the frontend menu, you should select the required element on the right and click the Add button.
    4. Click Save to confirm adding a new menu item for the top menu.
  3. Create a new CMS page.
    1. Navigate to Preferences -> CMS and click  Add new CMS page button:
      How_to_add_drop_down_menus_in_Top_Horizontal_Menu_module_5
    2. Fill in the choices suggested and click ‘Save’ button.
This CMS page will be displayed as a drop-down menu button for CMS category automatically:

Prestashop - Add multiple category trees with helper form

Question:

I'm creating a prestashop module which need to select 2 categories root.
I tried to add 2 fields with type "categories", but on the second category tree, it has the same ID and the same NAME as the first tree.
$fields_form[1]['form'] = array(
    'legend' => array(
        'title' => $this->l('Setting'),
    ),
    'input' => array(       
        array(
            'type'  => 'text',
            'label' => $this->l('First column title'),
            'name'  => 'HCA_TITLE_COL1',
        ),
        array(
           'type'  => 'categories',
           'label' => $this->l('Root category'),
           'desc'    => $this->l('Root category of the first column.'),  
           'name'  => 'HCA_CAT_COL1',
           'tree'  => array(
                'id' => 'HCA_CAT_COL1',
                'selected_categories' => array((int)Configuration::get('HCA_CAT_COL1')),
            )
        ),
        array(
            'type'  => 'text',
            'label' => $this->l('Second column title'),
            'name'  => 'HCA_TITLE_COL2',
        ),
        array(
           'type'  => 'categories',
           'label' => $this->l('Root category'),
           'desc'    => $this->l('Root category of the second column.'),  
           'name'  => 'HCA_CAT_COL2',
           'tree'  => array(
                'id' => 'HCA_CAT_COL2',
                'selected_categories' => array((int)Configuration::get('HCA_CAT_COL2')),
            )
        ),
    )

Answer:

Here is the solution I found after reading admin\themes\default\template\helpers\form\form.tpl
In this file, there is this condition
{elseif $input.type == 'categories_select'}
    {$input.category_tree}
So, I used 'type' = 'categories_select' instead of 'type' = 'categories', and I generated the categories trees manually.
$root = Category::getRootCategory();

//Generating the tree for the first column
$tree = new HelperTreeCategories('categories_col1'); //The string in param is the ID used by the generated tree
$tree->setUseCheckBox(false)
    ->setAttribute('is_category_filter', $root->id)
    ->setRootCategory($root->id)
    ->setSelectedCategories(array((int)Configuration::get('HCA_CAT_COL1')))
    ->setInputName('HCA_CAT_COL1'); //Set the name of input. The option "name" of $fields_form doesn't seem to work with "categories_select" type
$categoryTreeCol1 = $tree->render();

//Generating the tree for the second column
$tree = new HelperTreeCategories('categories_col2');
$tree->setUseCheckBox(false)
     ->setAttribute('is_category_filter', $root->id)
     ->setRootCategory($root->id)
     ->setSelectedCategories(array((int)Configuration::get('HCA_CAT_COL2')))
     ->setInputName('HCA_CAT_COL2');
$categoryTreeCol2 = $tree->render();


$fields_form[1]['form'] = array(
    'legend' => array(
        'title' => $this->l('Setting'),
    ),
    'input' => array(       
        array(
            'type'  => 'text',
            'label' => $this->l('First column title'),
            'name'  => 'HCA_TITLE_COL1',
        ),
        array(
           'type'  => 'categories_select',
           'label' => $this->l('Root category'),
           'desc'    => $this->l('Root category of the first column.'),  
           'name'  => 'HCA_CAT_COL1',
           'category_tree'  => $categoryTreeCol1 //This is the category_tree called in form.tpl
        ),
        array(
            'type'  => 'text',
            'label' => $this->l('Second column title'),
            'name'  => 'HCA_TITLE_COL2',
        ),
        array(
           'type'  => 'categories_select',
           'label' => $this->l('Root category'),
           'desc'    => $this->l('Root category of the second column.'),  
           'name'  => 'HCA_CAT_COL2',
           'category_tree'  => $categoryTreeCol2
        ),
    )
);
 

Prestashop select attribute combination photos

Question:
Short version : I want to get product photos that are assigned to product's attribute groups. Long version : I want to accomplish the feature by creating a custom module : on product page, you can choose a product color by choosing from a list of product's photos representing different colors, just like here : http://www.kupbuty.com/product-pol-6941-Komin-wzor-w-koleczka-SZ-MRA-110-Granat.html (sorry that it's polish, but I think you'll get the idea). I've already accomplished to get the attributes groups of a product with distinct colours by using the code below (I get all attribute groups and if I haven't got a group with a given color name already then I add it to array $colors):
$attr=$product->getAttributesGroups($this->context->language->id);
$colors=array();
$exists=array();
foreach ($attr as $key => $a) {
   if($a['id_attribute_group']==Configuration::get($this->name.'_attr_id'))
      {
         if(!in_array($a['attribute_name'], $exists))
         {
            $colors[]=$a;
            $exists[]=$a['attribute_name'];
         }
       }
}
Now I looked into Product class and I can't understand how I can get images associated with selected product groups. I've also printed whole $colors content, but I did not see any relevant fields. The images are correctly assigned to attributs combinations in the admin. Can you point me in some direction? EDIT : To make myself more clear - I want to get PRODUCT'S PHOTO assigned to specific attribute value - let's say I have shoes that can be black or white, I want to get white shoe image and black shoe image. The attributes are organized in combinations (I think it's now called "groups"?) of color and size, and every combination has a set of photos - I want to access this photos list.
 
Answer:
You won't find anything useful into the Product class because the attribute-image association done on Prestashop for Attributes value is done in a silly and simply way. when you save an image associated to an attribute, a image file is created under the specific folder
_THEME_COL_DIR_
that is nothing more than the "co" subfolder under the prestashop image directory, with the id_attribute as namefile and jpg as file extension.
so for example if you want to check the image for the id_attribute 5, you will find it under: _THEME_COL_DIR.$id_attribute.'jpg' => '/img/co/5.jpg';
By working that way you will see that both in admin and on the frontend each time the attributes' images have to be shown the code is directly placed in the template, without any preprocessing involved on the Controller/Class.
for example in the product page, the product.tpl has something along the line of:
<a id="color_{$id_attribute|intval}" class="color_pick{if ($group.default == $id_attribute)} selected{/if}" style="background: {$colors.$id_attribute.value};" title="{$colors.$id_attribute.name}" onclick="colorPickerClick(this);getProductAttribute();{if $colors|@count > 0}$('#wrapResetImages').show('slow');{/if}">
        {if file_exists($col_img_dir|cat:$id_attribute|cat:'.jpg')}
        <img src="{$img_col_dir}{$id_attribute}.jpg" alt="{$colors.$id_attribute.name}" width="20" height="20" /><br>
        {/if} ... </a>
where both the image existance and the url are created directly in the template by simply using the img_col_dir and the id_attribute

Prestashop set multiple select from the module and get them in the input

Question:
I am doing a small module in Prestashop. In that module I have used multiselect with helperform. So my code is like this
array(
    'type' => 'select',
    'cols' => 8,
    'class' => 'chosen-product-selct selected_products ',
    'multiple' => true,
    'label' => $this->l('Selected Products'),
    'name' => 'selected_products[]',
    'options' => array(
        'query' => $product_query,
        'id' => 'id',
        'name' => 'product_name'
    ),
    'desc' => $this->l('Select products from products list.'),
),
Here I am saving those multiselected values to the database. But when I am doing edit no saved values has been selected in the box. The box is totally empty.
for getting the result I am doing this
public function getConfigFieldsValues() {
    'selected_products[]'  => Tools::getValue('selected_products', Configuration::get('selected_products')),
}
Its not showing the values that has been entered.So can someone tell me how to solve this issue? Any help and suggestions will be really appreciable. Thanks
Amswer:
I found a solution to the problem with Prestashop multiple select form helper issue.
In order for the select box to work properly there are the following requirements:
  1. Input name should have '[]'. For example: manufacturer_ids[]
  2. $fields_value array should have this element with the same name: manufacturer_ids[] not manufacturer_ids.
  3. The value of the $fields_value array's corresponding item should have selected values as array. For example:
    $fields_value['manufacturer_ids[]'] = array("120", "145");
I save the submitted values as sarialized string in Database, so I am handling it this way:
    $selectedManufacturers = @unserialize($manufacturerIdsTakenFromDb);
    if ($selectedManufacturers === false && $selectedManufacturers !== 'b:0;') {
        $selectedManufacturers = array();
    }        
    $fields_value['manufacturer_ids[]'] = $selectedManufacturers;
And my code in form definition looks like this:
array(
    'type' => 'select',
    'label' => $this->l('Manufacturers'),
    'name' => 'manufacturer_ids[]',
    'multiple' => true,
    'options' => array(
        'query' => array(
            array('key' => '1', 'name' => 'Apple'),
            array('key' => '2', 'name' => 'Samsung'),
            array('key' => '3', 'name' => 'HTC'),
        ),
        'id' => 'key',
        'name' => 'name'
    )
),
If your code does satisfy all these and it still does not work, please let me know, I will be happy to assist you to fix it.

Third party modules in mailalert on prestashop

Question:
I have a custom module that I'm using on prestashop 1.5.4.1 and I need to show some information on the new_order email. I'm quite new to prestashop and it's the first time I'm messing with it.. I wanna know how I can get the variable of that module and show it on the email template.
I already found where the new_order mail variables are set, but don't know how I can add my new custom variable to it.
Any help will be appreciated. Thanks!
 
Answer:
You should override the PaymentModule class and add your custom variable to the email template.
Copy the validateOrder method from classes/PaymentModule.php
Create override/classes/PaymentModule.php and paste the validateOrder method:
<?php
class PaymentModule extends PaymentModuleCore
{
  //paste validateOrder here
}
Find the following line in validateOrder:
'{delivery_other}' => $delivery->other,
After that line assign your custom variable. For example:
'{delivery_date}' => $myDeliveryDate,
Remove /cache/class_index.php to clear the cache.
Copy order_conf.html and order_conf.txt from mails/en to themes/YOURTHEME/mails/en if they are not already there. This will prevent PrestaShop updates to overwrite your changes.
Add your custom variable to the new order_conf.html and order_conf.txt. For example:
<tr>
  <td align="left">Delivery date: {delivery_date}</td>
</tr>     

Prestashop autocomplete

Queation:
Im trying to add very simple autocomplete function to my prestashop addon input. What I want to achieve is something like this:
city.php
<label for="city">City: </label>
And auto.js
$(function() {
var availableTags = [
  "London",
  "Manchester",
  "Liverpool",
];
$( "#city" ).autocomplete({
  source: availableTags
});
The problem is that I dont know how to call jquery library in prestashop. I was trying to add something like this in my addon class:
$this->context->controller->addJqueryPlugin('autocomplete');
With no luck...
 
Answer:
1:In controllers you can add any JS files with
$this->addJS(_THEME_JS_DIR_.'index.js');
So, you can put this plugin to theme_folder/js/plugins/autocomplite.js and add it with $this->addJS(_THEME_JS_DIR_.'plugins/autocomplite.js');
2:
In Prestashop 1.6, using hook function, you can do something like this (actualy i'm using it inside a custom module) :
public function hookHeader() {
    //Jquery native Prestashop plugin
    $this->context->controller->addJQueryPlugin('fancybox');
    //CSS
    $this->context->controller->addCSS('//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css', 'all');
    $this->context->controller->addCSS('//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css', 'all');
    $this->context->controller->addCSS('//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.15.35/css/bootstrap-datetimepicker.css', 'all');
    $this->context->controller->addCSS('//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.15.35/css/bootstrap-datetimepicker.min.css', 'all');
    //Javascript
    $this->context->controller->addJS('//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js', 'all');
    $this->context->controller->addJS('//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js', 'all');
    $this->context->controller->addJS('//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.js', 'all');
    $this->context->controller->addJS('//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js', 'all');
    $this->context->controller->addJS('//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/locale/fr.js', 'all');
    $this->context->controller->addJS('//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.15.35/js/bootstrap-datetimepicker.min.js', 'all');
}
As you can see, i'm adding Fancybox, Bootstrap and DateTimePicker. You should add your own plugins inside js directory, inside your theme or module.
Calling a plugin in theme is easy using smarty ($js_dir i guess, or $tpl_dir)
EDIT :
Here's a sample of autocomplete in Prestashop :
TPL :
<!-- Block eversearch module TOP -->
<div id="search_block_top" class="col-sm-4 clearfix">
    <form id="searchbox" method="get" action="{$link->getPageLink('search')|escape:'html':'UTF-8'}" >
        <input type="hidden" name="controller" value="search" />
        <input type="hidden" name="orderby" value="position" />
        <input type="hidden" name="orderway" value="desc" />
        <input class="search_query form-control" type="text" id="search_query_top" name="search_query" placeholder="{l s='Search' mod='blocksearch'}" value="{$search_query|escape:'htmlall':'UTF-8'|stripslashes}" />
        <button type="submit" name="submit_search" class="btn btn-default button-search">
            <span>{l s='Search' mod='blocksearch'}</span>
        </button>
    </form>
And here's autocomplete using Jquery :
$(document).ready(function(){
//console.log('Autocomplete loaded');
var baseUrl = $('#baseURL').val();
var evertrade_module_dir = baseUrl+'/useful';
var form = $('.ever_search_query_top');
//console.log(baseUrl);
//Autocomplete
$('#ever_search_query_top').autocomplete(evertrade_module_dir+'/ajax_product_list.php', {
    minChars: 1,
    autoFill: true,
    max:20,
    matchContains: true,
    mustMatch:true,
    scroll:false,
    cacheLength:0,
    formatItem: function(item) {
        return item[1];

    }
}).result(function(e,i){ 
    console.log(i);
    if(i != undefined)
        $('#ever_search_query_top').val(i[1]);
        window.location.href = baseUrl+"recherche?orderby=position&orderway=desc&search_query="+i[1]+"";
});
Assuming your php file is returning correct values. Prefere use your own HTML, overriding tpl in your theme.

PrestaShop. How to fix the blank product page issue

This tutorial shows how to fix the blank product page issue in PrestaShop.
Today we will show how you can fix the blank page appearing instead of your product page when you click on the product.
The issue of the blank product page can occur in PrestaShop due to the following reasons:
  • upgrading Prestoshop version from the previous ones (1.4.x, 1.5.x)
  • server settings
  • third party modules installed
  • migration from subdomain to domain
To fix the blank product page, please try the possible fixes below:
  1. Clear smarty and web brwoser cache, especially if the problem appeared after moving your site from subdomain to domain.
  2. If any third party modules were installed, go to Modules -> Modules in your admin and disable the module(s):
    PrestaShop_How_to_fix_the_blank_product_page_issue_1
  3. Deleting and regenerating the .htaccess file can solve the problem.
    In order to do it, delete the .htaccess file from the root directory on the server using FTP or in cPanel (do not forget to make a back up of the file first) and refresh your front office:
    PrestaShop_How_to_fix_the_blank_product_page_issue_2
  4. Another thing worth doing is activating a debug mode and setting _PS_MODE_DEV_ to true. Please note that this fix is mostly used for Prestashop 1.5.
    To activate a debug mode, you need to open config/config.inc.php file on your server and find the following lines:

    1
    2
    @ini_set('display_errors', 'off');
    define('_PS_DEBUG_SQL_', false)
    change ‘off’ to ‘on’ and false to true, like this:

    1
    @ini_set('display_errors', 'on');<br>define('_PS_DEBUG_SQL_', true);
    We strongly recommend that you make a back up before modifying the file.
    Besides, you may need to change the setting for _PS_MODE_DEV_. Open config/defines.inc.php file on the server and find the following line:

    1
    define('_PS_MODE_DEV_', false);
    change it to

    1
    define('_PS_MODE_DEV_', true);
    Be sure to make a back up before editing the file:
    PrestaShop_How_to_fix_the_blank_product_page_issue_3
  5. One more possible solution is increasing memory limit for the site.
    This can be done either by adding the following code in config.inc.php:

    1
    ini_set('memory_limit','128M');
    or edit memory limit in the php.ini located in the root of your Prestashop installation folder (if you do not have such a file in the root of your site folder, you can simply create a new text file and name it “php.ini” and upload it on the server):

    1
    memory_limit = 256M;
    PrestaShop_How_to_fix_the_blank_product_page_issue_4
Please note that the above described methods may not always help depending on the circumstances and environment of your Prestashop site. In this case, we recommend that you visit Prestashop official forum or/and contact your hosting provider.

Prestashop no errors / blank page

Question:
I'm developing a module in PHP for Prestashop and I'm having a tough time trying to debug code. Whenever something falls over it doesn't display errors, just a blank page - either on the front end where the module is hooked, or on the back end module page.
I'm trying to write in another class, or another function but it doesn't like it at all.
It's on a local dev server, PHP errors are on etc.
Can somebody tell me any other way to debug stuff instead of commenting out code? Or some way of getting error codes?
Thanks for your help in advance.
 
Answer:
 As1:
Try opening config/config.inc.php and then change:
@ini_set('display_errors', 'off')
to
@ini_set('display_errors', 'on').

From PS 1.5+, you need to open config/defines.inc.php and change:
define('_PS_MODE_DEV_', false);
to
define('_PS_MODE_DEV_', true);
 
AS2: check this out for the final solution!
First of all, you need to enable errors reporting on your website.
1) Open the file config\config.inc.php and find the following line:
@ini_set(‘display_errors’, off’);    
2) Change ‘off’ to ‘on’, re-upload the file and refresh your page.
If it doesn’t help, go to the next step.
3)Add this code to the top of your index.php file in the root of PrestaShop installation and re-upload it on your server. Then try to access your website and admin panel.
    <?php error_reporting(0); 
       $old_error_handler = set_error_handler("userErrorHandler");

       function userErrorHandler ($errno, $errmsg, $filename, $linenum,  $vars) 
     {
     $time=date("d M Y H:i:s"); 
     // Get the error type from the error number 
     $errortype = array (1    => "Error",
                         2    => "Warning",
                         4    => "Parsing Error",
                     8    => "Notice",
                     16   => "Core Error",
                     32   => "Core Warning",
                     64   => "Compile Error",
                     128  => "Compile Warning",
                     256  => "User Error",
                     512  => "User Warning",
                     1024 => "User Notice");
  $errlevel=$errortype[$errno];

  //Write error to log file (CSV format) 
  $errfile=fopen("errors.csv","a"); 
  fputs($errfile,"\"$time\",\"$filename: 
  $linenum\",\"($errlevel) $errmsg\"\r\n"); 
  fclose($errfile);

  if($errno!=2 && $errno!=8) {
     //Terminate script if fatal error
     die("A fatal error has occurred. Script execution has been aborted");
  } 
   }
?>
After this manipulations you will find the file called errors.csv in the folder where your index.php file is located. Download and open the file errors.csv using any text editor, you will find the error log there.

Wednesday, April 22, 2015

Adding a module front and admin controller in Prestashop 1.6

Recently I have started Prestashop module development for 1.6. Mine is a simple module to add SSO and another for adding custom fields to back-office order management. A process of the back-office order management will allow posting a cronjob. Anyway, the core part is, I needed to create a controller in the module (both front and admin controller). To add a module front controller create a file like /modules/<my_module>/controllers/front/<controller>.php. Then the class inside the front controller should look like this:

class <my_module><controller>FrontController extends ModuleFrontController

The route to this will be like <my_prestashop_host>/index.php?fc=module&module=<my_module>&controller=<controller
Also to create the back-office admin controller for you module create a file in /modules/<my_module>/controllers/admin/<controller>.php. The class definition should be:
class <controller>Controller extends ModuleAdminController
The route to this should look like <my_prestashop_host>/<admin_dir>/index.php?controller=<controllerThe most important part of the admin controller is Tab configuration. Make sure, in the install procedure of the module you register a tab something like this:

$tab = new Tab();
$tab->active = 1;
$tab->name = array();
$tab->class_name = '<controller>';


foreach (Language::getLanguages(true) as $lang) {
$tab->name[$lang['id_lang']] = '<my controller description text>';
}
$tab->id_parent = -1;
$tab->module = <my_module>;
$tab->add();

Make sure the record is there in ps_tab table.
Prestashop Themes Wordpress themes

Tuesday, March 31, 2015

Cách chống hack nick facebook

Gần đây có một số bọn hay đi hack nick facebook, vợ mình cũng bị nên tìm hiểu và thấy nếu chúng ta có thể thiết lập một vài bước và sẽ tránh không bị hack facebook, kể cả không may cài những app hay link vớ vẩn: chọn edit cái Login Approvals-> check vào cái checkbox như này khi nào có người dùng trình duyệt trên máy tính khác đăng nhập facebook của các bạn nó se yêu cầu nhập mã code bảo vệ gửi về điện thoại các bạn, nhớ là đừng làm mất cả số điện thoại nhé 



Các bạn click vào Login Alerts 
Hy vọng giúp được mọi người không bị mất nick face và bị làm phiền

Monday, March 30, 2015

prestashop error Problem: Admin/Backend login redirect in version 1.6

1/ Clear your browser cache and your cookies 2/ Try using Firefox instead of Chrome (which seems have some unexpected problems) 3/ Check PS_SHOP_DOMAIN and PS_SHOP_DOMAIN_SSL in ps_configuration table 4/ Manually clear smarty cache : remove all files from tools/smarty/compile and tools/smarty/cache 5/ Disable the IP check in classes/Cookie.php (this can causes many issues with dynamics IP) : in isLoggedBack(), remove or comment the fourth condition : AND (!isset($this->_content['remote_addr']) OR $this->_content['remote_addr'] == ip2long(Tools::getRemoteAddr()) OR !Configuration::get('PS_COOKIE_CHECKIP')) 6/ Make the expire time shorter for cookies (IE can have issues with longest time cookies) : in classes/Cookie.php constructor, set : $this->_expire = isset($expire) ? (int)($expire) : (time() + 3600); instead of $this->_expire = isset($expire) ? (int)($expire) : (time() + 1728000);

Tuesday, March 17, 2015

wordpress: Writing a Plugin

Introduction

WordPress Plugins allow easy modification, customization, and enhancement of a WordPress blog. Instead of changing the core programming of WordPress, you can add functionality with WordPress Plugins. Here is a basic definition:
WordPress Plugin: A WordPress Plugin is a program, or a set of one or more functions, written in the PHP scripting language, that adds a specific set of features or services to the WordPress weblog, which can be seamlessly integrated with the weblog using access points and methods provided by the WordPress Plugin Application Program Interface (API).
Wishing that WordPress had some new or modified functionality? The first thing to do is to search various WordPress Plugin repositories and sources to see if someone has already created a WordPress Plugin that suits your needs. If not, this article will guide you through the process of creating your own WordPress Plugin.
This article assumes you are already familiar with the basic functionality of WordPress, and PHP programming.
Resources




  • To understand how WordPress Plugins work and how to install them on your WordPress blog, see Plugins.
  • There is a comprehensive list of articles and resources for Plugin developers, including external articles on writing WordPress Plugins, and articles on special topics, in Plugin Resources.
  • To learn the basics about how WordPress Plugins are written, view the source code for well-written Plugins, such as Hello Dolly distributed with WordPress.
  • Once you have written your WordPress Plugin, read Plugin Submission and Promotion to learn how to distribute it and share it with others.

Creating a Plugin

This section of the article goes through the steps you need to follow, and things to consider when creating a well-structured WordPress Plugin.

Names, Files, and Locations

Plugin Name

The first task in creating a WordPress Plugin is to think about what the Plugin will do, and make a (hopefully unique) name for your Plugin. Check out Plugins and the other repositories it refers to, to verify that your name is unique; you might also do a Google search on your proposed name. Most Plugin developers choose to use names that somewhat describe what the Plugin does; for instance, a weather-related Plugin would probably have the word "weather" in the name. The name can be multiple words.

Plugin Files

The next step is to create a PHP file with a name derived from your chosen Plugin name. For instance, if your Plugin will be called "Fabulous Functionality", you might call your PHP file fabulous-functionality.php. Again, try to choose a unique name. People who install your Plugin will be putting this PHP file into the WordPress Plugins directory in their installation (usually wp-content/plugins/), so no two Plugins they are using can have the same PHP file name.
Another option is to split your Plugin into multiple files. Your WordPress Plugin must have at least one PHP file; it could also contain JavaScript files, CSS files, image files, language files, etc. If there are multiple files, pick a unique name for a directory and a name of your choice (usually the same) for the main PHP file of your Plugin, such as fabulous-functionality and fabulous-functionality.php, respectively, put all your Plugin's files into that directory, and tell your Plugin users to install the whole directory under wp-content/plugins/. Notice that WordPress installation can be configured for wp-content/plugins/ directory to be moved, so you must use plugin_dir_path() and plugins_url() for absolute paths and URLs. See: http://codex.wordpress.org/Determining_Plugin_and_Content_Directories for more details.
In the rest of this article, "the Plugin PHP file" refers to the main Plugin PHP file, whether in wp-content/plugins/ or a sub-directory.
Security Note: Consider blocking direct access to your plugin PHP files by adding the following line at the top of each of them, or be sure to refrain from executing sensitive standalone PHP code before calling any WordPress functions.
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );

Readme File

If you want to host your Plugin on http://wordpress.org/extend/plugins/, you also need to create a readme.txt file in a standard format, and include it with your Plugin. See http://wordpress.org/extend/plugins/about/readme.txt for a description of the format or use the automatic plugin 'readme.txt' generator.
Note that the WordPress plugin repository takes the "Requires" and "Tested up to" versions from the readme.txt in the stable tag.

Home Page

It is also very useful to create a web page to act as the home page for your WordPress Plugin. This page should describe how to install the Plugin, what it does, what versions of WordPress it is compatible with, what has changed from version to version of your Plugin, and how to use the Plugin.

File Headers

Now it's time to put some information into your main Plugin PHP file.

Standard Plugin Information

The top of your Plugin's main PHP file must contain a standard Plugin information header. This header lets WordPress recognize that your Plugin exists, add it to the Plugin management screen so it can be activated, load it, and run its functions; without the header, your Plugin will never be activated and will never run. Here is the header format:
<?php
/**
 * Plugin Name: Name of the plugin, must be unique.
 * Plugin URI: http://URI_Of_Page_Describing_Plugin_and_Updates
 * Description: A brief description of the plugin.
 * Version: The plugin's version number. Example: 1.0.0
 * Author: Name of the plugin author
 * Author URI: http://URI_Of_The_Plugin_Author
 * Text Domain: Optional. Plugin's text domain for localization. Example: mytextdomain
 * Domain Path: Optional. Plugin's relative directory path to .mo files. Example: /locale/
 * Network: Optional. Whether the plugin can only be activated network wide. Example: true
 * License: A short license name. Example: GPL2
 */
The minimum information WordPress needs to recognize your Plugin is the Plugin Name line. The rest of the information (if present) will be used to create the table of Plugins on the Plugin management screen. The order of the lines is not important.
So that the upgrade mechanism can correctly read the Version of your plugin it is recommended that you pick a format for the version number and stick to it between the different releases. For example, x.x or x.x.x or xx.xx.xxx
Text Domain is optional. Must be a unique identifier for translation and the same as the one used in load_plugin_textdomain().
Domain Path is optional. Specify a path if the translations are located in a folder above the plugin's base path. Example: if .mo files are located in the locale folder then Domain Path will be /locale/ and must have the first slash. If not added, defaults to the base folder the plugin is located in.
Network is optional. Specify true to require that a plugin is activated across all sites in an installation. This will prevent a plugin from being activated on a single site when Multisite is enabled. You don't need to add this line if the plugin can be activated in network-wide mode and single site mode.
License is not read by WordPress but is meant to be a simple way of being explicit about the license of the code. The slug should be a short common identifier for the license the plugin is under.
Important: file must be in UTF-8 encoding.

License

It is customary to follow the standard header with information about licensing for the Plugin. Most Plugins use the GPL2 license used by WordPress or a license compatible with the GPL2. To indicate a GPL2 license, include the following lines in your Plugin:
<?php
/*  Copyright YEAR  PLUGIN_AUTHOR_NAME  (email : PLUGIN AUTHOR EMAIL)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License, version 2, as 
    published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

Programming Your Plugin

Now, it's time to make your Plugin actually do something. This section contains some general ideas about Plugin development, and describes how to accomplish several tasks your Plugin will need to do.

WordPress Plugin Hooks

Many WordPress Plugins accomplish their goals by connecting to one or more WordPress Plugin "hooks". The way Plugin hooks work is that at various times while WordPress is running, WordPress checks to see if any Plugins have registered functions to run at that time, and if so, the functions are run. These functions modify the default behavior of WordPress.
For instance, before WordPress adds the title of a post to browser output, it first checks to see if any Plugin has registered a function for the "filter" hook called "the_title". If so, the title text is passed in turn through each registered function, and the final result is what is printed. So, if your Plugin needs to add some information to the printed title, it can register a "the_title" filter function.
Another example is the "action" hook called "wp_footer". Just before the end of the HTML page WordPress is generating, it checks to see whether any Plugins have registered functions for the "wp_footer" action hook, and runs them in turn.
You can learn more about how to register functions for both filter and action hooks, and what Plugin hooks are available in WordPress, in the Plugin API. If you find a spot in the WordPress code where you'd like to have an action or filter, but WordPress doesn't have one, you can also suggest new hooks (suggestions will generally be taken); see Reporting Bugs to find out how.

Template Tags

Another way for a WordPress Plugin to add functionality to WordPress is by creating custom Template Tags. Someone who wants to use your Plugin can add these "tags" to their theme, in the sidebar, post content section, or wherever it is appropriate. For instance, a Plugin that adds geographical tags to posts might define a template tag function called geotag_list_states() for the sidebar, which lists all the states posts are tagged with, with links to the state-based archive pages the Plugin enables.
To define a custom template tag, simply write a PHP function and document it for Plugin users on your Plugin's home page and/or in the Plugin's main PHP file. It's a good idea when documenting the function to give an example of exactly what needs to be added to the theme file to use the function, including the <?php and ?>.

Saving Plugin Data to the Database

Most WordPress Plugins will need to get some input from the site owner or blog users and save it between sessions, for use in its filter functions, action functions, and template functions. This information has to be saved in the WordPress database, in order to be persistent between sessions. There are four (4) methods for saving Plugin data in the database:
  1. Use the WordPress "option" mechanism (described below). This method is appropriate for storing relatively small amounts of relatively static, named pieces of data -- the type of data you'd expect the site owner to enter when first setting up the Plugin, and rarely change thereafter.
  2. Post Meta (a.k.a. Custom Fields). Appropriate for data associated with individual posts, pages, or attachments. See post_meta Function Examples, add_post_meta(), and related functions.
  3. Custom Taxonomy. For classifying posts or other objects like users and comments and/or for a user-editable name/value list of data consider using a Custom Taxonomy, especially when you want to access all posts/objects associated with a given taxonomy term. See Custom Taxonomies.
  4. Create a new, custom database table. This method is appropriate for data not associated with individual posts, pages, attachments, or comments -- the type of data that will grow as time goes on, and that doesn't have individual names. See Creating Tables with Plugins for information on how to do this.

WordPress Options Mechanism

See Creating Options Pages for info on how to create a page that will automatically save your options for you.
WordPress has a mechanism for saving, updating, and retrieving individual, named pieces of data ("options") in the WordPress database. Option values can be strings, arrays, or PHP objects (they will be "serialized", or converted to a string, before storage, and unserialized when retrieved). Option names are strings, and they must be unique, so that they do not conflict with either WordPress or other Plugins.
It's also generally considered a good idea to minimize the number of options you use for your plugin. For example, instead of storing 10 different named options consider storing a serialized array of 10 elements as a single named option.
Here are the main functions your Plugin can use to access WordPress options.
add_option($name, $value, $deprecated, $autoload);
Creates a new option; does nothing if option already exists.
$name
Required (string). Name of the option to be added.
$value
Optional (mixed), defaults to empty string. The option value to be stored.
$deprecated
Optional (string), no longer used by WordPress, You may pass an empty string or null to this argument if you wish to use the following $autoload parameter.
$autoload
Optional, defaults to 'yes' (enum: 'yes' or 'no'). If set to 'yes' the setting is automatically retrieved by the wp_load_alloptions function.
get_option($option);
Retrieves an option value from the database.
$option
Required (string). Name of the option whose value you want returned. You can find a list of the default options that are installed with WordPress at the Option Reference.
update_option($option_name, $newvalue);
Updates or creates an option value in the database (note that add_option does not have to be called if you do not want to use the $deprecated or $autoload parameters).
$option_name
Required (string). Name of the option to update.
$newvalue
Required. (string|array|object) The new value for the option.

Administration Panels

Assuming that your Plugin has some options stored in the WordPress database (see section above), you will probably want it to have an administration panel that will enable your Plugin users to view and edit option values. The methods for doing this are described in Adding Administration Menus.

Internationalizing Your Plugin

Once you have the programming for your Plugin done, another consideration (assuming you are planning on distributing your Plugin) is internationalization. Internationalization is the process of setting up software so that it can be localized; localization is the process of translating text displayed by the software into different languages. WordPress is used all around the world, so it has internationalization and localization built into its structure, including localization of Plugins.
Please note that language files for Plugins ARE NOT automatically loaded. Add this to the Plugin code to make sure the language file(s) are loaded:
 load_plugin_textdomain('your-unique-name', false, basename( dirname( __FILE__ ) ) . '/languages' );
To fetch a string simply use __('String name','your-unique-name'); to return the translation or _e('String name','your-unique-name'); to echo the translation. Translations will then go into your plugin's /languages folder.
It is highly recommended that you internationalize your Plugin, so that users from different countries can localize it. There is a comprehensive reference on internationalization, including a section describing how to internationalize your plugin, at I18n for WordPress Developers.

Updating Your Plugin

This section describes the necessary steps to update your Plugin when you host it on http://wordpress.org/extend/plugins, including details about using Subversion (SVN) with wordpress.org.
Assuming you have already submitted your Plugin to the WordPress Plugin Repository, over time you will probably find the need, and hopefully the time, to add features to your Plugin or fix bugs. Work on these changes and commit the changes to the trunk of your plugin as often as you want. The changes will be publicly visible, but only to the technically-minded people checking out your Plugin via SVN. What other users download through the website or their WordPress Plugin administration will not change.
When you're ready to release a new version of the Plugin:
  • Make sure everything is committed and the new version actually works. Pay attention to all WordPress versions your Plugin supports and try to test it with all of them. Don't just test the new features; also make sure you didn't accidentally break some older functionality of the Plugin.
  • Change the version number in the header comment of the main PHP file to the new version number (in the trunk folder).
  • Change the version number in the 'Stable tag' field of the readme.txt file (in the trunk folder).
  • Add a new sub-section in the 'changelog' section of the readme.txt file, briefly describing what changed compared to the last release. This will be listed on the 'Changelog' tab of the Plugin page.
  • Commit these changes.
  • Create a new SVN tag as a copy of trunk, following this guide.
Give the system a couple of minutes to work, and then check the wordpress.org Plugin page and a WordPress installation with your Plugin to see if everything updated correctly and the WordPress installation shows an update for your Plugin (the update checks might be cached, so this could take some time -- try visiting the 'available updates' page in your WordPress installation).
Troubleshooting:
  • The Plugin's page on wordpress.org still lists the old version. Have you updated the 'stable tag' field in the trunk folder? Just creating a tag and updating the readme.txt in the tag folder is not enough!
  • The Plugin's page offers a zip file with the new version, but the button still lists the old version number and no update notification happens in your WordPress installations. Have you remembered to update the 'Version' comment in the main PHP file?
  • For other problems check Otto's good write-up of common problems: The Plugins directory and readme.txt files

Plugin Development Suggestions

This last section contains various suggestions regarding Plugin development.
  • The code of a WordPress Plugin should follow the WordPress Coding Standards. Please consider the Inline Documentation Standards as well.
  • All the functions in your Plugin need to have unique names that are different from functions in the WordPress core, other Plugins, and themes. For that reason, it is a good idea to use a unique function name prefix on all of your Plugin's functions. A far superior possibility is to define your Plugin functions inside a class (which also needs to have a unique name).
  • Do not hardcode the WordPress database table prefix (usually "wp_") into your Plugins. Be sure to use the $wpdb->prefix variable instead.
  • Database reading is cheap, but writing is expensive. Databases are exceptionally good at fetching data and giving it to you, and these operations are (usually) lightning quick. Making changes to the database, though, is a more complex process, and computationally more expensive. As a result, try to minimize the amount of writing you do to the database. Get everything prepared in your code first, so that you can make only those write operations that you need.
  • Use WordPress' APIs instead of using direct SQL where possible. For example, use get_posts() or new WP_Query() instead of SELECT * FROM {$wpdb->prefix}_posts.
  • Use the existing database tables instead of creating new custom tables if possible. Most use-cases can be accomplished with custom post types and meta data, custom taxonomy and/or one of the other standard tables and using the standard tables provides a lot of UI and other functionality "for free." Think very carefully before adding a table because it adds complexity to your plugin that many users and site builders prefer to avoid.
  • SELECT only what you need. Even though databases fetch data blindingly fast, you should still try to reduce the load on the database by only selecting that data which you need to use. If you need to count the number of rows in a table don't SELECT * FROM, because all the data in all the rows will be pulled, wasting memory. Likewise, if you only need the post_id and the post_author in your Plugin, then just SELECT those specific fields, to minimize database load. Remember: hundreds of other processes may be hitting the database at the same time. The database and server each have only so many resources to spread around amongst all those processes. Learning how to minimize your Plugin's hit against the database will ensure that your Plugin isn't the one that is blamed for abuse of resources.
  • Eliminate PHP errors in your plugin. Add define('WP_DEBUG', true); to your wp-config.php file, try all of your plugin functionality, and check to see if there are any errors or warnings. Fix any that occur, and continue in debug mode until they have all been eliminated.
  • Try not to echo <script> and <style> tags directly - instead use the recommended wp_enqueue_style() and wp_enqueue_script() functions. They help eliminate including duplicate scripts and styles as well as introduce dependency support. See posts by the following people for more info: Ozh Richard, Artem Russakovskii, and Vladimir Prelovac.

External Resources