Wednesday, September 24, 2014

My First WordPress Plugin - Tutorial Part 3

In the previous tutorials;

  • Tutorial-1 :  It describes the general idea of what a plugin is in WordPress and what are the basics to create a plugin and a simple illustration of manipulating the content using filter.

  • Tutorial-2 : It focuses on creating a simple custom post type and taxonomies and  meta boxes to input additional information providing the user a flexible way to create their own menu, pages and labels.
In this tutorial, we will go through a process to create a plugin that enables to add custom pages to the admin menu section and provide the user with an ability to create and store data in the custom designed database table.

Database Table Creation:

Our plugin stores the data in a user designed database table instead of WP database. So, as soon as plugin is activated, a check for the table availability is done with an activation hook and a database table is created.
register_activation_hook( __FILE__, 'function-to-create-database-table' );
function function-to-create-database-table(){
global $wpdb;
$table_name = $wpdb->prefix. 'table-name';
if($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
   $sql="CREATE TABLE $table_name(
    //tables fields
    ) ";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
}
Now, the table with the user defined field has been created.

Admin Pages Creation:

 Admin Pages is our custom menu where we have our freedom to create the menu as our need. In our case, we are creating two menus; one to show, edit and delete the data and another one to add the data to the user created table.
add_action('admin_menu','page-to-view-items');
add_action('admin_menu','page-add-items');
function page-to-view-items(){
add_menu_page();
}
function page-add-items(){
add_submenu_page();
}
Now that we have created a admin menu and sub-menu. Suppose if we are creating the plugin for products, lets include a  menu Product and and sub-menu Add Products. Menu-Product is linked to a php file to represent all the data in table and an option to edit them while sub-menu Add Product contains the product add form. Lets have a peek to the add form.

Sub-Menu (Data Addition Form):

It contains normal html form to submit the data and you can create a custom css as per the design requirement. Inorder to insert the form data into the custom database table, the code is as below:
global $wpdb;
$table_name = $wpdb->prefix. 'table-name';
$field1=$_POST["field1"];//retrieving the data from the form using post method
$field2=$_POST["field2"];
$field3=$_POST["field3"];
  $wpdb->insert(
$table_name,
array(
'table-field-1' =>$field1,
'table-field-2' => $field2,
'table-field-3' => $field3
)
);

Displaying Data In Table:

For displaying the data, the easiest way is to use the default WordPress table so that the look and nature of the table is similar to the WordPress post display UI. 
<div class="wrap">
  <div class="icon32" id="icon-edit"><br></div>
  <h2><?php _e('Title') ?></h2>
<form method="post" action="" id="update_action">
<table class="widefat page fixed" cellpadding="0">
      <thead>
        <tr>
        <th id="cb" class="manage-column column-cb check-column" style="" scope="col">
          <input type="checkbox"/>
        </th>
          <th class="manage-column"><?php _e('title 1')?></th>
          <th class="manage-column"><?php _e('title 2')?></th>
          <th class="manage-column"><?php _e('title 3')?></th>
          <th class="manage-column"><?php _e('title 4')?></th>
        </tr>
      </thead>
      <tfoot>
        <tr>
        <th id="cb" class="manage-column column-cb check-column" style="" scope="col">
          <input type="checkbox"/>
        </th>
          <th class="manage-column"><?php _e('title 1')?></th>
          <th class="manage-column"><?php _e('title 2')?></th>
          <th class="manage-column"><?php _e('title 3')?></th>
          <th class="manage-column"><?php _e('title 4')?></th>
        </tr>
      </tfoot>
      <tbody>
        <?php
          $table = function-to-call-all-data();
          if($table){
           $i=0;
           foreach($table as $data) {
               $i++;
        ?>
      <tr class="<?php echo (ceil($i/2) == ($i/2)) ? "" : "alternate"; ?>">
        <th class="check-column" scope="row">
          <input type="checkbox" value="<?php echo $data->id?>" name="bor_id[]" />
        </th>
          <td>
          <strong><?php echo $data->db-table-field-1?></strong>
          <div class="row-actions-visible">
          <span class="edit"><a href="?page=redirect -to-edit-function-page-(page-title)">Edit</a> | </span>
          <span class="delete"><a href="?page=redirect -to-delete-function-page-(page-title)" onclick="return confirm('Are you sure you want to delete this software?');">Delete</a></span>
          </div>
          </td>
          <td><?php echo $data->db-table-field-2?></td>
          <td><?php echo $data->db-table-field-3?></td>
          <td><?php echo $data->db-table-field-4 ?></td>
        </tr>
        <?php
           }
        }
        else{
      ?>
        <tr><td colspan="4"><?php _e('There are no data.')?></td></tr>
        <?php
      }
        ?>
      </tbody>
    </table>
 </form>
</div> 

To this level, we have created a post like page UI and added the function to edit and delete the data from the table. To edit/update and delete the data, WordPress has a function to do that.
$wpdb->update(
$table_name,
array(
'db-field-1' =>$field-1-data,
'db-field-2' => $field-2-data,
'db-field-3' => $field-3-data
),
array( 'id' => $id ),
array(
'%s',
'%s',
'%d'
)
);
To delete the row, just data id is required and the rest is below.
$wpdb->delete($table_name,array('id'=>$id)); 

Android Expandable List View Tutorial

Expandable list view is used to group list data by categories. It has the capability of expanding and collapsing the groups when user touches header of list view. When u click on the header of list view it expands and when u again click on the same header it collapse. Like in below figures...

                         
                               Fig 1: Expanding Mode
Fig 2: Collapsing Mode

Some time we need to extend group header by default, for this
 we have following bits of code..
expandableList.expandGroup(0); //expand first position by default
expandableList.expandGroup(1); //expand second position by default

One more thing sometime we need to disable the collapsing feature in expandable list view for this we have ,
expandableList.setOnGroupClickListener(new OnGroupClickListener() {

@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
if(groupPosition==0)//disable collapsing feature of group header first position
                                   {
                                      return true;
}else{
return false;
}
}

});
In override the onGroupClick method. If true, the expandableListView thinks that the ability to expand and collapse has been handled. If false then it has not been handled, and will take care of the action. 

To generate expandable list view in project we need three layouts, one Adapter and one Main Activity.
The three layout goes like this....
1. main_activity.xml 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <ExpandableListView
        android:id="@+id/expandableList"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

2. list_group.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="10dp" >
    <TextView
        android:id="@+id/listHeader"
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
        android:textSize="16sp" />
</LinearLayout>

3. list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="55dip"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/listItem"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="17dip"
        android:paddingTop="5dp"
        android:paddingBottom="5dp"
        android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft" />
</LinearLayout>

Now we have to create ExpandableListAdapter.java like this...
For import -> ctrl + alt +o  
public class ExpandableListAdapter extends BaseExpandableListAdapter {
   private Context context;
   private List<String> listDataHeader;   // header titles
   private HashMap<String, List<String>> listDataChild;

   public ExpandableListAdapter(Context context, List<String> listDataHeader,
           HashMap<String, List<String>> listChildData) {
       this.context = context;
       this.listDataHeader = listDataHeader;
       this.listDataChild = listChildData;
   }
   @Override
   public Object getChild(int groupPosition, int childPosititon) {
       return this.listDataChild.get(this.listDataHeader.get(groupPosition))
               .get(childPosititon);
   }
   @Override
   public long getChildId(int groupPosition, int childPosition) {
       return childPosition;
   }  
   @Override
   public View getChildView(int groupPosition, final int childPosition,
           boolean isLastChild, View convertView, ViewGroup parent) {
       final String childText = (String) getChild(groupPosition, childPosition);
       if (convertView == null) {
           LayoutInflater infalInflater = (LayoutInflater) this._context
                   .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
           convertView = infalInflater.inflate(R.layout.list_item, null);
       }
       TextView txtListChild = (TextView) convertView
               .findViewById(R.id.listItem);
       txtListChild.setText(childText);
       return convertView;
   }
   @Override
   public int getChildrenCount(int groupPosition) {
       return this.listDataChild.get(this.listDataHeader.get(groupPosition))
               .size();
   }  
   @Override
   public Object getGroup(int groupPosition) {
       return this.listDataHeader.get(groupPosition);
   } 
   @Override
   public int getGroupCount() {
       return this.listDataHeader.size();
   } 
   @Override
   public long getGroupId(int groupPosition) {
       return groupPosition;
   } 
   @Override
   public View getGroupView(int groupPosition, boolean isExpanded,
           View convertView, ViewGroup parent) {
       String headerTitle = (String) getGroup(groupPosition);
       if (convertView == null) {
           LayoutInflater infalInflater = (LayoutInflater) this._context
                   .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
           convertView = infalInflater.inflate(R.layout.list_group, null);
       }
 
       TextView lblListHeader = (TextView) convertView
               .findViewById(R.id.listHeader);
       lblListHeader.setTypeface(null, Typeface.BOLD); //bold the header
       lblListHeader.setText(headerTitle);
 
       return convertView;
   }
 
   @Override
   public boolean hasStableIds() {
       return false;
   }
 
   @Override
   public boolean isChildSelectable(int groupPosition, int childPosition) {
       return true;
   }
}

Finally MainActivity.java goes like this...
For import ctrl + alt + o
public class MainActivity extends Activity {

ExpandableListAdapter listAdapter;
ExpandableListView expListView;
List<String> listDataHeader;
HashMap<String, List<String>> listDataChild;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// get the listview
expListView = (ExpandableListView) findViewById(R.id.expandableList);
getPrepareListData(); // preparing list data
listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild);
expListView.setAdapter(listAdapter); //set the  list adapter

// Listview Group click listener
expListView.setOnGroupClickListener(new OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
//do ur task
return false;
}
});

// Listview Group expanded listener
expListView.setOnGroupExpandListener(new OnGroupExpandListener() {

@Override
public void onGroupExpand(int groupPosition) {
//do ur task
}
});

// Listview Group collasped listener
expListView.setOnGroupCollapseListener(new OnGroupCollapseListener() {

@Override
public void onGroupCollapse(int groupPosition) {
//do ur task
}
});

// Listview on child click listener
expListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
// TODO Auto-generated method stub
//do ur task
return false;
}
});
}
private void getPrepareListData() {
listDataHeader = new ArrayList<String>();
listDataChild = new HashMap<String, List<String>>();
// Adding header data
listDataHeader.add("For One Room");
listDataHeader.add("For Two Rooms");
listDataHeader.add("For Flat");
listDataHeader.add("For House");
listDataHeader.add("For Apartment");
// Adding child data
List<String> one_room = new ArrayList<String>();
one_room.add("1 room at baneshwor, kathmandu");
one_room.add("1 room at sundhara, kathmandu");
one_room.add("1 room at pulchowk, lalitpur");
one_room.add("1 room at gwarko, lalitpur");
one_room.add("1 room at sundhara, lalitpur");
one_room.add("1 room at balkumari, lalitpur");
one_room.add("1 room at lazimpat, kathmandu");

List<String> two_room = new ArrayList<String>();
two_room.add("2 rooms at baneshwor, kathmandu");
two_room.add("2 rooms at sundhara, kathmandu");

List<String> flat = new ArrayList<String>();
flat.add("1 flat at baneshwor, kathmandu");
flat.add("1 flat at sundhara, kathmandu");

listDataChild.put(listDataHeader.get(0), one_room); // Header, Child listDataChild.put(listDataHeader.get(1), two_room);
listDataChild.put(listDataHeader.get(2), flat); //you can add others here
}
}

Friday, September 5, 2014

My First WordPress Plugin - Tutorial Part 2

WordPress is a very flexible framework, simple to use, easy to understand and developer friendly environment. To create a plugin in WordPress basic understanding of hook and filter and action is needed.  This tutorial will guide you through basic knowledge of hooks and filter and action and focused more importantly on plugin to Custom Post Type and Custom Taxonomy.

Hook:

In general, a hook is something that is particularly attached with another thing. As like that, hook defines the relation and dependency  between the functions and action or filter in WordPress.

  1. add_filter('the_content','helloworld');
  2. function helloworld($content){
  3. $content=$content."<br>Hello World. This is Semicolon Dev ";
  4. return $content;

Lets take the above example. Here, we have used a filter function to get the content and add certain text at the end.  Line 1 has a filter:  add_filter('first_argument','second_argument') ; The first argument is used to get the content/description of the post and second one helloworld is a call to a function. Here helloworld is a function hooked with the_content.

A hook is generally used to change the default nature of the WordPress. The above example is used to change the default behavior of normal posting to adding content to each post.

Action and Filter :

Action and Filter are alias; An action hook is used to perform certain action and insert code in the WordPress core while filer hook is used to perform certain task on the content and supposed to return a value and are associated with an action.

add_action($hook$function_to_add$priority$accepted_args );
add_filter$tag$function_to_add$priority$accepted_args ); 

Custom Post Type:

It is a WordPress linked word which is normally harder to understand. We have a admin menu-Post to the left so Custom post type is a method to create our own post type naming it, the way we prefer, providing the features we feel necessary.

function custom_post(){
$labels_post = array(
'name' =>_x( 'Products', 'post type general name' ),
'singular_name' =>_x( 'Product', 'post type singular name' ),
'add_new' =>_x( 'Add Product', 'product' ),
'all_items' =>__( 'Available Products' ),
'add_new_item' =>__( 'Add New Products' ),
'edit_item' =>__( 'Edit Product' ),
'new_item' =>__( 'New Product' ),
'view_item' =>__( 'View Products'),
'search_items' =>__( 'Search Products' ),
'menu_name' => 'Products'
);
$args= array(
'labels' => $labels_post,
'description' => 'Product Description',
'public' => true,
'supports'                => array( 'title', 'editor', 'thumbnail','comments' ),
'menu_position' => 10
);
register_post_type('name-of-the-post', $args);
}



Here, we have created a Product as a custom post type enabling the developer to customize the available field.

Custom Taxonomy:

Taxonomy is a method of grouping things under a particular heading as like category and tags which are used to bind the post with certain tags and under particular category. 

register_taxonomy'product_categories''name-of-the-post'$args );
The first argument is the name of the taxonomy, second one is the name of the post-type and last argument is an array which is used to define the necessary functions of the WordPress to be included.

The side figure shows that the tag field has been created where the capabilities to edit, add and remove can be defined during its creation.Here $args is similar to that of above $args on labels declaration but its characteristics is defined by other values;

'hierarchical'             => true,
'show_admin_column'           => true,
'show_ui'                              => true,
'rewrite'                   => array('slug' => 'product-category', 'with_front'                                                                           =>FALSE),
'capabilities'              => array('assign_terms' => 'edit_products',
                                                   'edit_terms'   => 'edit_products',
                                                   'manage_terms' => 'edit_others_products',
                                                   'delete_terms' => 'delete_others_products')
Meta Box:

If we are creating our custom type post then it is certain that we need extra information to be included with our post which can be done using meta-boxes.


Creating a meta box is a simple task of adding an action during the post creation and it is performed with the below code:

add_action('add_meta_boxes','product_price');
Using the hook add_meta_box , we are set to create a metabox and second argument is a function which contains the features like id,title and its parent post type of the meta box.

add_meta_box$id$title$callback$post_type$context,$priority$callback_args );

  • $callback is the  reference to a  function that determines the label and input types within the meta data.The reference function takes $post as argument and a nonce field is included which is required later for verification while saving the data. wp_nonce_field  has action name and nonce name.  
  • $post_type is the name of the custom post type.
Creating meta box does not mean WordPress is going to save the data. A separate action, to save the data in the meta box table of the wordpress, has to be defined as

add_action('save_post','function-name');
In this case, the function takes $post_id as argument and it has to first verify the data with the nonce and update the post.

wp_verify_nonce($_POST['nonce-name'], 'action-name' )
$variable = $_POST['name-of-the-input-field'];
update_post_meta( $post_id, 'metabox-id', $variable );


Now, we have created a Custom Type Post and Custom Taxonomy and able to include extra field like product price using the meta-box.


Thanks for reading. Stay tuned for more posts in the series.

 

© 2013 Echo "Semicolon Developers"; Kathmandu. All rights resevered @ Semicolon Developers Network Pvt. Ltd.. Designed by Templateism

Back To Top