Category

Category: AJAX

Using History.js with AJAX

Over the past decade, web applications have evolved to make heavy use of JavaScript in order to dynamically load content into web pages. One of the big challenges that developers face when creating these applications is preserving an accurate and useful browser history. Without this many of a browsers most used features, like the back and forward buttons, will not work as expected.

Aim

  • To store a history of every dynamically loaded pages.
  • To load dynamic contents base on the URL inputted / pasted directly into the brower’s URL bar.
  • To make the browser’s forward and backward buttons work.
  • To enable sharing of URLs or use them to create links from any HTML document.

History.JS currently supports a lot of JavaScript libraries, but for this example I will only be demonstrating how to use the jQuery version of History.JS in working with dynamic contents.

Demo

Logs

Using History.Log() we can check the data stored to the history of our browser in object representation.

Source Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script type="text/javascript" src="js/jquery.history.js"></script>
   
    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
         
</head>
<body>
    <br />
    <div class = "container">
        <nav class="navbar navbar-default">
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a href="home">Home</a></li>
                    <li><a href="about">About</a></li>
                    <li><a href="contact">Contact</a></li>     
                </ul>  
            </div>
        </nav>
        <div class = "content"></div>
    </div>
</body>

<script type='text/javascript'>
$(function(){
   
    var History = window.History;
   
    if (History.enabled) {
        var page = get_url_value('page');
        var path = page ? page : 'home';
        // Load the page
        load_page_content(path);
    } else {
        return false;
    }

    // Content update and back/forward button handler
    History.Adapter.bind(window, 'statechange', function() {
        var State = History.getState();
        // Do ajax
        load_page_content(State.data.path);
        // Log the history object to your browser's console
        History.log(State);
    });

    // Navigation link handler
    $('body').on('click', 'nav a', function(e) {
        e.preventDefault();
       
        var urlPath = $(this).attr('href');
        var title = $(this).text();
       
        History.pushState({path: urlPath}, title, './?page=' + urlPath); // When we do this, History.Adapter will also execute its contents.       
    });
   
    function load_page_content(page) {
        $.ajax({  
            type: 'post',
            url: page + '.html',
            data: {},                      
            success: function(response) {
                $('.content').html(response);
            }
        });
    }
   
    function get_url_value(variable) {
       var query = window.location.search.substring(1);
       var vars = query.split("&");
       for (var i=0;i<vars.length;i++) {
               var pair = vars[i].split("=");
               if(pair[0] == variable){return pair[1];}
       }
       return(false);
    }
});

</script>
</html>

AJAX Multi File Upload in WordPress Front-End

Step 1: Create a custom page in WordPress

  • Go to your Dashboard > Pages > Add New
  • Name the page anything you want, ex: Ajax Uploader
  • In your Dashboard > Settings > Permalinks, make sure Common Settings is set to Post Name
  • In the new page, copy the page slag: if you used “Ajax Uploader” as your page name, the slag would be ajax-uploader
  • In your WordPress theme create a file called page-ajax-uploader.php  Notice how we attached the slag to the “page-“, this will allow us to add custom scripts that will only apply to this specific page.
  • Go to your browser and navigate to your new page. ex. http://example.com/ajax-uploader It should show you a blank white page, if not then you did something incorrectly.

Step 2: Working on our page

  • Building the HTML Form
1
2
3
4
5
6
7
8
9
10
<div class = "col-md-6 upload-form">
    <div class= "upload-response"></div>
    <div class = "form-group">
        <label><?php __('Select Files:', 'cvf-upload'); ?></label>
        <input type = "file" name = "files[]" accept = "image/*" class = "files-data form-control" multiple />
    </div>
    <div class = "form-group">
        <input type = "submit" value = "Upload" class = "btn btn-primary btn-upload" />
    </div>
</div>

Javascript

  • Setup our form data to be sent via AJAX:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$(document).ready(function() {
    // When the Upload button is clicked...
    $('body').on('click', '.upload-form .btn-upload', function(e){
        e.preventDefault;

        var fd = new FormData();
        var files_data = $('.upload-form .files-data'); // The <input type="file" /> field
       
        // Loop through each data and create an array file[] containing our files data.
        $.each($(files_data), function(i, obj) {
            $.each(obj.files,function(j,file){
                fd.append('files[' + j + ']', file);
            })
        });
       
        // our AJAX identifier
        fd.append('action', 'cvf_upload_files');  
       
        // Remove this code if you do not want to associate your uploads to the current page.
        fd.append('post_id', <?php echo $post->ID; ?>);

        $.ajax({
            type: 'POST',
            url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
            data: fd,
            contentType: false,
            processData: false,
            success: function(response){
                $('.upload-response').html(response); // Append Server Response
            }
        });
    });
});
  • This is how your page-ajax-uploader.php template should look like:
  • Make sure you have the latest jQuery in your header.php
    1
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php get_header(); ?>

    <section class = "inner-page-wrapper">
        <section class = "container">
            <section class = "row content">
                <?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
                    <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                        <h1><?php the_title(); ?></h1>
                        <article class="entry-content">
                            <?php the_content(); ?>
                           
                            <div class = "col-md-6 upload-form">
                                <div class= "upload-response"></div>
                                <div class = "form-group">
                                    <label><?php __('Select Files:', 'cvf-upload'); ?></label>
                                    <input type = "file" name = "files[]" accept = "image/*" class = "files-data form-control" multiple />
                                </div>
                                <div class = "form-group">
                                    <input type = "submit" value = "Upload" class = "btn btn-primary btn-upload" />
                                </div>
                            </div>
                                                                                   
                            <script type = "text/javascript">
                            $(document).ready(function() {
                                // When the Upload button is clicked...
                                $('body').on('click', '.upload-form .btn-upload', function(e){
                                    e.preventDefault;

                                    var fd = new FormData();
                                    var files_data = $('.upload-form .files-data'); // The <input type="file" /> field
                                   
                                    // Loop through each data and create an array file[] containing our files data.
                                    $.each($(files_data), function(i, obj) {
                                        $.each(obj.files,function(j,file){
                                            fd.append('files[' + j + ']', file);
                                        })
                                    });
                                   
                                    // our AJAX identifier
                                    fd.append('action', 'cvf_upload_files');  
                                   
                                    // uncomment this code if you do not want to associate your uploads to the current page.
                                    fd.append('post_id', <?php echo $post->ID; ?>);

                                    $.ajax({
                                        type: 'POST',
                                        url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
                                        data: fd,
                                        contentType: false,
                                        processData: false,
                                        success: function(response){
                                            $('.upload-response').html(response); // Append Server Response
                                        }
                                    });
                                });
                            });                    
                            </script>
                           
                           
                        </article>
                    </article>
                <?php endwhile; ?>
            </section>
        </section>
    </section>
   
<?php get_footer(); ?>

Server Side Processing

  • Add the code bellow to your functions.php
  • Don’t forget to read thru the comments found within the codes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
add_action('wp_ajax_cvf_upload_files', 'cvf_upload_files');
add_action('wp_ajax_nopriv_cvf_upload_files', 'cvf_upload_files'); // Allow front-end submission

function cvf_upload_files(){
   
    $parent_post_id = isset( $_POST['post_id'] ) ? $_POST['post_id'] : 0;  // The parent ID of our attachments
    $valid_formats = array("jpg", "png", "gif", "bmp", "jpeg"); // Supported file types
    $max_file_size = 1024 * 500; // in kb
    $max_image_upload = 10; // Define how many images can be uploaded to the current post
    $wp_upload_dir = wp_upload_dir();
    $path = $wp_upload_dir['path'] . '/';
    $count = 0;

    $attachments = get_posts( array(
        'post_type'         => 'attachment',
        'posts_per_page'    => -1,
        'post_parent'       => $parent_post_id,
        'exclude'           => get_post_thumbnail_id() // Exclude post thumbnail to the attachment count
    ) );

    // Image upload handler
    if( $_SERVER['REQUEST_METHOD'] == "POST" ){
       
        // Check if user is trying to upload more than the allowed number of images for the current post
        if( ( count( $attachments ) + count( $_FILES['files']['name'] ) ) > $max_image_upload ) {
            $upload_message[] = "Sorry you can only upload " . $max_image_upload . " images for each Ad";
        } else {
           
            foreach ( $_FILES['files']['name'] as $f => $name ) {
                $extension = pathinfo( $name, PATHINFO_EXTENSION );
                // Generate a randon code for each file name
                $new_filename = cvf_td_generate_random_code( 20 )  . '.' . $extension;
               
                if ( $_FILES['files']['error'][$f] == 4 ) {
                    continue;
                }
               
                if ( $_FILES['files']['error'][$f] == 0 ) {
                    // Check if image size is larger than the allowed file size
                    if ( $_FILES['files']['size'][$f] > $max_file_size ) {
                        $upload_message[] = "$name is too large!.";
                        continue;
                   
                    // Check if the file being uploaded is in the allowed file types
                    } elseif( ! in_array( strtolower( $extension ), $valid_formats ) ){
                        $upload_message[] = "$name is not a valid format";
                        continue;
                   
                    } else{
                        // If no errors, upload the file...
                        if( move_uploaded_file( $_FILES["files"]["tmp_name"][$f], $path.$new_filename ) ) {
                           
                            $count++;

                            $filename = $path.$new_filename;
                            $filetype = wp_check_filetype( basename( $filename ), null );
                            $wp_upload_dir = wp_upload_dir();
                            $attachment = array(
                                'guid'           => $wp_upload_dir['url'] . '/' . basename( $filename ),
                                'post_mime_type' => $filetype['type'],
                                'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
                                'post_content'   => '',
                                'post_status'    => 'inherit'
                            );
                            // Insert attachment to the database
                            $attach_id = wp_insert_attachment( $attachment, $filename, $parent_post_id );

                            require_once( ABSPATH . 'wp-admin/includes/image.php' );
                           
                            // Generate meta data
                            $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
                            wp_update_attachment_metadata( $attach_id, $attach_data );
                           
                        }
                    }
                }
            }
        }
    }
    // Loop through each error then output it to the screen
    if ( isset( $upload_message ) ) :
        foreach ( $upload_message as $msg ){       
            printf( __('<p class="bg-danger">%s</p>', 'wp-trade'), $msg );
        }
    endif;
   
    // If no error, show success message
    if( $count != 0 ){
        printf( __('<p class = "bg-success">%d files added successfully!</p>', 'wp-trade'), $count );  
    }
   
    exit();
}

// Random code generator used for file names.
function cvf_td_generate_random_code($length=10) {
 
   $string = '';
   $characters = "23456789ABCDEFHJKLMNPRTVWXYZabcdefghijklmnopqrstuvwxyz";
 
   for ($p = 0; $p < $length; $p++) {
       $string .= $characters[mt_rand(0, strlen($characters)-1)];
   }
 
   return $string;
 
}

WordPress Front-end AJAX Pagination with Search and Sort

I posted a tutorial a year ago about creating an AJAX Pagination in your WordPress front-end, in this tutorial I would like to show how you can integrate a Search Filter and Sorting functionality. This tutorial also covers how you can go back to previous page state (pagination number and applied sorting filter) after visiting a post then clicking the back button in your browser.

wordpress-front-end-ajax-pagination-with-search-and-sort-screenshot
Demo

Step 1: Create a custom page in WordPress

  • Go to your Dashboard > Pages > Add New
  • Name the page anything you want, ex: My Posts
  • In your Dashboard > Settings > Permalinks, make sure Common Settings is set to Post Name
  • In your newly created page, copy the page slag: if you used “My Posts” as your page name, the slag would be my-posts
  • In your WordPress theme create a file called page-my-posts.php  Notice how we attached the slag to the “page-“, this will allow us to add custom scripts that will only apply to this specific page.
  • Go to your browser and navigate to your new page. ex. http://example.com/my-posts It should show you a blank white page, if not then you did something incorrectly.

Step 2: Working on our page

  • Open the new page and paste the following code template:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?php get_header(); ?>
    <div class  ="col-md-12 content">
        <div class = "content">
            <form class = "post-list">
                <input type = "hidden" value = "" />
            </form>
            <?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
                <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                    <h1 class="entry-title"><?php the_title(); ?></h1>                                                                                 
                    <hr />
                    <article class="entry-content clear">
                        <?php the_content(); ?>
                    </article>
                </article>
            <?php endwhile; ?> 
           
            <article class="navbar-form navbar-left">
                <div class="form-group">
                    <input type="text" class="form-control post_search_text" placeholder="Enter a keyword">
                </div>
                <input type = "submit" value = "Search" class = "btn btn-success post_search_submit" />
            </article>
           
            <br class = "clear" />
           
            <script type="text/javascript">
            var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
           
            function cvf_load_all_posts(page, th_name, th_sort){
                $(".cvf_universal_container").html('<p><img src = "<?php bloginfo('template_url'); ?>/images/loading.gif" class = "loader" /></p>');
               
                var post_data = {
                    page: page,
                    search: $('.post_search_text').val(),
                    th_name: th_name,
                    th_sort: th_sort
                };
               
                $('form.post-list input').val(JSON.stringify(post_data));
               
                var data = {
                    action: "demo_load_my_posts",
                    data: JSON.parse($('form.post-list input').val())
                };
               
                $.post(ajaxurl, data, function(response) {
                    if($(".cvf_universal_container").html(response)){
                        $('.table-post-list th').each(function() {
                            // Append the button indicator
                            $(this).find('span.glyphicon').remove();   
                            if($(this).hasClass('active')){
                                if(JSON.parse($('form.post-list input').val()).th_sort == 'DESC'){
                                    $(this).append(' <span class="glyphicon glyphicon-chevron-down"></span>');
                                } else {
                                    $(this).append(' <span class="glyphicon glyphicon-chevron-up"></span>');
                                }
                            }
                        });
                    }
                });
            }
           
            jQuery(document).ready(function($) {                                                               
               
                // Initialize default item to sort and it's sort order
               
                // Check if our hidden form input is not empty, meaning it's not the first time viewing the page.
                if($('form.post-list input').val()){
                    // Submit hidden form input value to load previous page number
                    data = JSON.parse($('form.post-list input').val());
                    cvf_load_all_posts(data.page, data.th_name, data.th_sort);
                } else {
                    // Load first page
                    cvf_load_all_posts(1, 'post_title', 'ASC');
                }
               
                var th_active = $('.table-post-list th.active');
                var th_name = $(th_active).attr('id');
                var th_sort = $(th_active).hasClass('DESC') ? 'ASC': 'DESC';
                           
                // Search
                $('body').on('click', '.post_search_submit', function(){
                    cvf_load_all_posts(1, th_name, th_sort);
                });
                // Search when Enter Key is triggered
                $(".post_search_text").keyup(function (e) {
                    if (e.keyCode == 13) {
                        cvf_load_all_posts(1, th_name, th_sort);
                    }
                });
               
                // Pagination Clicks                   
                $('.cvf_universal_container .cvf-universal-pagination li.active').live('click',function(){
                    var page = $(this).attr('p');
                    var current_sort = $(th_active).hasClass('DESC') ? 'DESC': 'ASC';
                    cvf_load_all_posts(page, th_name, current_sort);               
                });

                // Sorting Clicks
                $('body').on('click', '.table-post-list th', function(e) {
                    e.preventDefault();                            
                    var th_name = $(this).attr('id');
                                                       
                    if(th_name){
                        // Remove all TH tags with an "active" class
                        if($('.table-post-list th').removeClass('active')) {
                            // Set "active" class to the clicked TH tag
                            $(this).addClass('active');
                        }
                        if(!$(this).hasClass('DESC')){
                            cvf_load_all_posts(1, th_name, 'DESC');
                            $(this).addClass('DESC');
                        } else {
                            cvf_load_all_posts(1, th_name, 'ASC');
                            $(this).removeClass('DESC');
                        }
                    }
                })
            });
            </script>
           
            <table class = "table table-striped table-post-list no-margin">
                <tr>
                    <th width = "25%" class = "active" id = "post_title"><u><a href = "#">Post Name</a></u></th>
                    <th width = "60%">Description</th>
                    <th width = "15%" id = "post_date"><u><a href = "#">Post Date</a></u></th>
                </tr>
            </table>
           
            <div class = "cvf_pag_loading no-padding">
                <div class = "cvf_universal_container">
                    <div class="cvf-universal-content"></div>
                </div>
            </div>
        </div>
    </div>
   
<?php get_footer(); ?>
  • Explanations are on the codes
  • This tutorial make use of bootstrap classes, so I suggest including bootstrap on the header part of your website:
1
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />

Step 3: Add the following PHP Code to your functions.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
add_action( 'wp_ajax_demo_load_my_posts', 'demo_load_my_posts' );
add_action( 'wp_ajax_nopriv_demo_load_my_posts', 'demo_load_my_posts' );
function demo_load_my_posts() {
       
    global $wpdb;
   
    $msg = '';
   
    if( isset( $_POST['data']['page'] ) ){
        // Always sanitize the posted fields to avoid SQL injections
        $page = sanitize_text_field($_POST['data']['page']); // The page we are currently at
        $name = sanitize_text_field($_POST['data']['th_name']); // The name of the column name we want to sort
        $sort = sanitize_text_field($_POST['data']['th_sort']); // The order of our sort (DESC or ASC)
        $cur_page = $page;
        $page -= 1;
        $per_page = 15; // Number of items to display per page
        $previous_btn = true;
        $next_btn = true;
        $first_btn = true;
        $last_btn = true;
        $start = $page * $per_page;
       
        // The table we are querying from  
        $posts = $wpdb->prefix . "posts";
       
        $where_search = '';
       
        // Check if there is a string inputted on the search box
        if( ! empty( $_POST['data']['search']) ){
            // If a string is inputted, include an additional query logic to our main query to filter the results
            $where_search = ' AND (post_title LIKE "%%' . $_POST['data']['search'] . '%%" OR post_content LIKE "%%' . $_POST['data']['search'] . '%%") ';
        }
       
        // Retrieve all the posts
        $all_posts = $wpdb->get_results($wpdb->prepare("
            SELECT * FROM $posts WHERE post_type = 'post' AND post_status = 'publish' $where_search
            ORDER BY $name $sort LIMIT %d, %d"
, $start, $per_page ) );
       
        $count = $wpdb->get_var($wpdb->prepare("
            SELECT COUNT(ID) FROM "
. $posts . " WHERE post_type = 'post' AND post_status = 'publish' $where_search", array() ) );
       
        // Check if our query returns anything.
        if( $all_posts ):
            $msg .= '<table class = "table table-striped table-hover table-file-list">';
           
            // Iterate thru each item
            foreach( $all_posts as $key => $post ):
                $msg .= '
                <tr>
                    <td width = "25%"><a href = "'
. get_permalink( $post->ID ) . '">' . $post->post_title . '</a></td>
                    <td width = "60%">'
. $post->post_excerpt . '</td>
                    <td width = "15%">'
. $post->post_date . '</td>
                </tr>'
;        
            endforeach;
           
            $msg .= '</table>';
       
        // If the query returns nothing, we throw an error message
        else:
            $msg .= '<p class = "bg-danger">No posts matching your search criteria were found.</p>';
           
        endif;

        $msg = "<div class='cvf-universal-content'>" . $msg . "</div><br class = 'clear' />";
       
        $no_of_paginations = ceil($count / $per_page);

        if ($cur_page >= 7) {
            $start_loop = $cur_page - 3;
            if ($no_of_paginations > $cur_page + 3)
                $end_loop = $cur_page + 3;
            else if ($cur_page <= $no_of_paginations && $cur_page > $no_of_paginations - 6) {
                $start_loop = $no_of_paginations - 6;
                $end_loop = $no_of_paginations;
            } else {
                $end_loop = $no_of_paginations;
            }
        } else {
            $start_loop = 1;
            if ($no_of_paginations > 7)
                $end_loop = 7;
            else
                $end_loop = $no_of_paginations;
        }
         
        $pag_container .= "
        <div class='cvf-universal-pagination'>
            <ul>"
;

        if ($first_btn && $cur_page > 1) {
            $pag_container .= "<li p='1' class='active'>First</li>";
        } else if ($first_btn) {
            $pag_container .= "<li p='1' class='inactive'>First</li>";
        }

        if ($previous_btn && $cur_page > 1) {
            $pre = $cur_page - 1;
            $pag_container .= "<li p='$pre' class='active'>Previous</li>";
        } else if ($previous_btn) {
            $pag_container .= "<li class='inactive'>Previous</li>";
        }
        for ($i = $start_loop; $i <= $end_loop; $i++) {

            if ($cur_page == $i)
                $pag_container .= "<li p='$i' class = 'selected' >{$i}</li>";
            else
                $pag_container .= "<li p='$i' class='active'>{$i}</li>";
        }
       
        if ($next_btn && $cur_page < $no_of_paginations) {
            $nex = $cur_page + 1;
            $pag_container .= "<li p='$nex' class='active'>Next</li>";
        } else if ($next_btn) {
            $pag_container .= "<li class='inactive'>Next</li>";
        }

        if ($last_btn && $cur_page < $no_of_paginations) {
            $pag_container .= "<li p='$no_of_paginations' class='active'>Last</li>";
        } else if ($last_btn) {
            $pag_container .= "<li p='$no_of_paginations' class='inactive'>Last</li>";
        }

        $pag_container = $pag_container . "
            </ul>
        </div>"
;
       
        echo
        '<div class = "cvf-pagination-content">' . $msg . '</div>' .
        '<div class = "cvf-pagination-nav">' . $pag_container . '</div>';
       
    }
   
    exit();
   
}

Step 4: Add some CSS styling to our Pagination navigation:

  • Include the following code in your style.css:
1
2
3
4
5
6
.cvf_pag_loading {padding: 20px; }
.cvf-universal-pagination ul {margin: 0; padding: 0;}
.cvf-universal-pagination ul li {display: inline; margin: 3px; padding: 4px 8px; background: #FFF; color: black; }
.cvf-universal-pagination ul li.active:hover {cursor: pointer; background: #1E8CBE; color: white; }
.cvf-universal-pagination ul li.inactive {background: #7E7E7E;}
.cvf-universal-pagination ul li.selected {background: #1E8CBE; color: white;}

Building a Real-Time Chat Application Using Pusher

824b1c56-87f0-11e1-9712-8f15a4b24539

Demo

WebSockets is an advanced technology that makes it possible to open an interactive communication session between the user’s browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply. In this tutorial we are going to create a simple chat application using Pusher. Pusher is a simple hosted API for quickly, easily and securely adding realtime bi-directional functionality via WebSockets to web and mobile apps, or any other Internet connected device.

Browser Support

Old browsers do not support WebSockets, you need latest browser that supports HTML5 WebSocket features, Please see caniuse.com to find-out all WebSocket supported browsers.

Scripts we need for our Chat Application:

  • jQuery
  • Pusher
  • Bootstrap JS and CSS (For the UI)
  • Bootbox (For our alert box)
  • Custom Styles

Create a Pusher Account

Step 1. Create an account at www.pusher.com
Step 2. Login to your pusher account then create an App, name it anything you want.
Step 3. After you have successfully created your app – the following will be generated: app_id, key, and secret.
Step 4. Go over the codes in this tutorial and replace the following: ‘your_app_id’, ‘your_app_key’, ‘your_app_secret’ with your app_id, key, and secret.
Step 5. Test the chat application in your server or local machine. Use 2 different browsers for the testing.


The Tutorial

Include the following code in the header part of your file.

1
2
3
4
5
6
7
8
9
10
11
12
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js" type="text/javascript" ></script>
<script src="//js.pusher.com/2.2/pusher.min.js" type="text/javascript" type="text/javascript" ></script>   
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript" ></script>  
<script src="//cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.3.0/bootbox.min.js" type="text/javascript" ></script>

<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<style = "text/css">
<!--       
.messages_display {height: 300px; overflow: auto;}     
.messages_display .message_item {padding: 0; margin: 0; }      
.bg-danger {padding: 10px;} -->
</style>

Create the chat form:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class = "container">      
    <div class = "col-md-6 chat_box">                      
        <div class = "form-control messages_display"></div>        
        <br />                     
        <div class = "form-group">             
            <label>Name</label>            
            <input type = "text" class = "input_name form-control" placeholder = "Name" />         
        </div>                     
        <div class = "form-group">             
            <label>Message</label>             
            <textarea class = "input_message form-control" placeholder = "Message"></textarea>         
        </div>                     
        <div class = "form-group input_send_holder">               
            <input type = "submit" value = "Send" class = "btn btn-primary input_send" />          
        </div>                 
    </div> 
</div>

Client Side script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<script type="text/javascript">        
// Enter your own Pusher App key
var pusher = new Pusher('your_app_key');
// Enter a unique channel you wish your users to be subscribed in.
var channel = pusher.subscribe('test_channel');
channel.bind('my_event', function(data) {
    // Add the new message to the container
    $('.messages_display').append('<p class = "message_item">' + data.message + '</p>');
    // Display the send button
    $('.input_send_holder').html('<input type = "submit" value = "Send" class = "btn btn-primary input_send" />');
    // Scroll to the bottom of the container when a new message becomes available
    $(".messages_display").scrollTop($(".messages_display")[0].scrollHeight);
});

// AJAX request
function ajaxCall(ajax_url, ajax_data) {
    $.ajax({
        type: "POST",
        url: ajax_url,
        dataType: "json",
        data: ajax_data,
        success: function(response, textStatus, jqXHR) {
            console.log(jqXHR.responseText);
        },
        error: function(msg) {}
    });
}

// Trigger for the Enter key when clicked.
$.fn.enterKey = function(fnc) {
    return this.each(function() {
        $(this).keypress(function(ev) {
            var keycode = (ev.keyCode ? ev.keyCode : ev.which);
            if (keycode == '13') {
                fnc.call(this, ev);
            }
        });
    });
}

// Send the Message
$('body').on('click', '.chat_box .input_send', function(e) {
    e.preventDefault();
   
    var message = $('.chat_box .input_message').val();
    var name = $('.chat_box .input_name').val();
   
    // Validate Name field
    if (name === '') {
        bootbox.alert('<br /><p class = "bg-danger">Please enter a Name.</p>');
   
    } else if (message !== '') {
        // Define ajax data
        var chat_message = {
            name: $('.chat_box .input_name').val(),
            message: '<strong>' + $('.chat_box .input_name').val() + '</strong>: ' + message
        }
        // Send the message to the server
        ajaxCall('message_relay.php', chat_message);
       
        // Clear the message input field
        $('.chat_box .input_message').val('');
        // Show a loading image while sending
        $('.input_send_holder').html('<input type = "submit" value = "Send" class = "btn btn-primary" disabled /> &nbsp;<img src = "loading.gif" />');
    }
});

// Send the message when enter key is clicked
$('.chat_box .input_message').enterKey(function(e) {
    e.preventDefault();
    $('.chat_box .input_send').click();
});
</script>

Server Side Script (message_relay.php):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
require('lib/Pusher.php');

// Change the following with your app details:
// Create your own pusher account @ www.pusher.com
$app_id = 'your_app_id'; // App ID
$app_key = 'your_app_key'; // App Key
$app_secret = 'your_app_secret'; // App Secret
$pusher = new Pusher($app_key, $app_secret, $app_id);

// Check the receive message
if(isset($_POST['message']) && !empty($_POST['message'])) {    
    $data['message'] = $_POST['message'];  
   
    // Return the received message
    if($pusher->trigger('test_channel', 'my_event', $data)) {              
        echo 'success';        
    } else {       
        echo 'error';  
    }
}

AJAX Multi-File Upload With Image Preview and Sort [Under Development]

I was looking into making this possible but I got stuck on the way.

1
<input type = "file" />

I believe the above code is the culprit on this Project since the way it store the files is randomized, therefore making it almost impossible to re-sort the images inside it.

The Codes bellow will work most of the time, and sometimes it will fail due to queueing issues on the input file.

Client Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Upload images with Jquery</title>
    <link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
   
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script type="text/javascript" src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.3.0/bootbox.min.js"></script>       <script type="text/javascript" src="jquery-2.1.3.min.js"></script>
    <script type="text/javascript" src="jquery-ui.js"></script>
   
    <style>
        ul.cvf_uploaded_files {list-style-type: none; margin: 20px 0 0 0; padding: 0;}
        ul.cvf_uploaded_files li {background-color: #fff; border: 1px solid #ccc; border-radius: 5px; float: left; margin: 20px 20px 0 0; padding: 2px; width: 150px; height: 150px; line-height: 150px; position: relative;}
        ul.cvf_uploaded_files li img.img-thumb {width: 150px; height: 150px;}
        ul.cvf_uploaded_files .ui-selected {background: red;}
        ul.cvf_uploaded_files .highlight {border: 1px dashed #000; width: 150px; background-color: #ccc; border-radius: 5px;}
        ul.cvf_uploaded_files .delete-btn {width: 24px; border: 0; position: absolute; top: -12px; right: -14px;}
        .bg-success {padding: 7px;}
    </style>
    <script type="text/javascript">
        jQuery(document).ready(function() {        
           
            var storedFiles = [];      
            //$('.cvf_order').hide();
           
            // Apply sort function 
            function cvf_reload_order() {
                var order = $('.cvf_uploaded_files').sortable('toArray', {attribute: 'item'});
                $('.cvf_hidden_field').val(order);
            }
           
            function cvf_add_order() {
                $('.cvf_uploaded_files li').each(function(n) {
                    $(this).attr('item', n);
                });
                console.log('test');
            }
           
           
            $(function() {
                $('.cvf_uploaded_files').sortable({
                    cursor: 'move',
                    placeholder: 'highlight',
                    start: function (event, ui) {
                        ui.item.toggleClass('highlight');
                    },
                    stop: function (event, ui) {
                        ui.item.toggleClass('highlight');
                    },
                    update: function () {
                        //cvf_reload_order();
                    },
                    create:function(){
                        var list = this;
                        resize = function(){
                            $(list).css('height','auto');
                            $(list).height($(list).height());
                        };
                        $(list).height($(list).height());
                        $(list).find('img').load(resize).error(resize);
                    }
                });
                $('.cvf_uploaded_files').disableSelection();
            });
                   
            $('body').on('change', '.user_picked_files', function() {
               
                var files = this.files;
                var i = 0;
                           
                for (i = 0; i < files.length; i++) {
                    var readImg = new FileReader();
                    var file = files[i];
                   
                    if (file.type.match('image.*')){
                        storedFiles.push(file);
                        readImg.onload = (function(file) {
                            return function(e) {
                                $('.cvf_uploaded_files').append(
                                "<li file = '" + file.name + "'>" +                                
                                    "<img class = 'img-thumb' src = '" + e.target.result + "' />" +
                                    "<a href = '#' class = 'cvf_delete_image' title = 'Cancel'><img class = 'delete-btn' src = 'delete-btn.png' /></a>" +
                                "</li>"
                                );     
                            };
                        })(file);
                        readImg.readAsDataURL(file);
                       
                    } else {
                        alert('the file '+ file.name + ' is not an image<br/>');
                    }
                   
                    if(files.length === (i+1)){
                        setTimeout(function(){
                            cvf_add_order();
                        }, 1000);
                    }
                }
            });
           
            // Delete Image from Queue
            $('body').on('click','a.cvf_delete_image',function(e){
                e.preventDefault();
                $(this).parent().remove('');       
               
                var file = $(this).parent().attr('file');
                for(var i = 0; i < storedFiles.length; i++) {
                    if(storedFiles[i].name == file) {
                        storedFiles.splice(i, 1);
                        break;
                    }
                }
               
                //cvf_reload_order();
               
            });
                   
            // AJAX Upload
            $('body').on('click', '.cvf_upload_btn', function(e){
               
                e.preventDefault();
                cvf_reload_order();
               
                //$(".cvf_uploaded_files").html('<p><img src = "loading.gif" class = "loader" /></p>');
                var data = new FormData();
               
                var items_array = $('.cvf_hidden_field').val();
                var items = items_array.split(',');

                for (var i in items){
                    var item_number = items[i];
                    data.append('files' + i, storedFiles[item_number]);
                }
                   
                $.ajax({
                    url: 'upload.php',
                    type: 'POST',
                    contentType: false,
                    data: data,
                    processData: false,
                    cache: false,
                    success: function(response, textStatus, jqXHR) {
                        //$(".cvf_uploaded_files").html('');                                               
                        //bootbox.alert('<br /><p class = "bg-success">File(s) uploaded successfully.</p>');
                        alert(jqXHR.responseText);
                    }
                });
               
            });        

        });
    </script>
</head>
<body>
    <div class = "container-fluid">
        <h3>Sort Files before upload</h3>
        <br />
        <div class = "col-md-6">
           
            <div class = "form-group">
                <label>Select Images</label>
                <input type = "file" name = "upload" multiple = "multiple" class = "form-control user_picked_files" />                 
            </div>                     
           
            <div class = "form-group cvf_order">                           
                <label>Order</label>                               
                <input type = "text" class = "form-control cvf_hidden_field" value = "" disabled = "disabled" />   
            </div>                     
           
            <input type = "submit" class = "cvf_upload_btn btn btn-primary" value = "Upload" />
           
            <ul class = "cvf_uploaded_files"></ul>
           
        </div>
    </div>
</body>
</html>

Server Script (upload.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

if(isset($_FILES)){
   
    $i = 1;
    foreach($_FILES as $key => $data){
           
        if (move_uploaded_file($data['tmp_name'], __DIR__ . '/uploads/' . $i . '--' . $data['name'])) {
            //echo "success";
            print_r($data['name']);
        } else {
            //echo "error";
        }
       
        $i++;
    }
}

AJAX Multi File upload in CodeIgniter

Uploading files asynchronously can be a pain at the best of times, but when coupled with CodeIgniter, it can be a particularly frustrating experience. Gladly, there is now a very easy way to upload multiple files using jQuery Form Plugin.

I assume you have a working knowledge of CodeIgniter and jQuery, and that you already have installed and set-up CodeIgniter.

Download the Multi File Upload Extension

Download Extension for Codeiginiter version 3.0 and above:

or download support for version 2.2 and bellow

Installation: Simply copy the MY_Upload.php file to application/libraries directory.

Creating the Upload Form

Using a text editor, create a form called upload_form.php. In it, place this code and save it to your applications/views/upload folder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<html>
<head>
<script type = "text/javascript" src = "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<script type = "text/javascript" src = "//cdnjs.cloudflare.com/ajax/libs/jquery.form/3.51/jquery.form.js"></script>
<title>Upload Form</title>
</head>
<body>
    <!-- AJAX Response will be outputted on this DIV container -->
    <div class = "upload-image-messages"></div>

    <div class = "col-md-6">
        <!-- Generate the form using form helper function: form_open_multipart(); -->
        <?php echo form_open_multipart('upload/do_upload', array('class' => 'upload-image-form'));?>
            <input type="file" multiple = "multiple" accept = "image/*" class = "form-control" name="uploadfile[]" size="20" /><br />
            <input type="submit" name = "submit" value="Upload" class = "btn btn-primary" />
        </form>

        <script>                   
        jQuery(document).ready(function($) {

            var options = {
                beforeSend: function(){
                    // Replace this with your loading gif image
                    $(".upload-image-messages").html('<p><img src = "<?php echo base_url() ?>images/loading.gif" class = "loader" /></p>');
                },
                complete: function(response){
                    // Output AJAX response to the div container
                    $(".upload-image-messages").html(response.responseText);
                    $('html, body').animate({scrollTop: $(".upload-image-messages").offset().top-100}, 150);
                   
                }
            }; 
            // Submit the form
            $(".upload-image-form").ajaxForm(options); 

            return false;
           
        });
        </script>
    </div>
</body>
</html>

You’ll notice we are using a form helper to create the opening form tag. File uploads require a multipart form, so the helper creates the proper syntax for you.

The Controller

Using a text editor, create a controller called upload.php. In it, place this code and save it to your applications/controllers/ folder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?php

class Upload extends CI_Controller {

    public function __construct() {
   
        parent::__construct();
        // Load the helpers
        $this->load->helper(array('form', 'url'));
    }

    public function index() {
       
        // Load the form
        $this->load->view('templates/header');
        $this->load->view('upload/upload_form', array('error' => ' ' ));
        $this->load->view('templates/footer');
       
    }
   
    /**
     * Multiple upload functionality will fallback to CodeIgniters default do_upload()
     * method so configuration is backwards compatible between do_upload() and the new do_multi_upload()
     * method provided by Multi File Upload extension.
     *
     */

    public function do_upload(){
   
        // Detect form submission.
        if($this->input->post('submit')){
       
            $path = './uploads/';
            $this->load->library('upload');
           
            /**
             * Refer to https://ellislab.com/codeigniter/user-guide/libraries/file_uploading.html
             * for full argument documentation.
             *
             */

             
            // Define file rules
            $this->upload->initialize(array(
                "upload_path"       =>  $path,
                "allowed_types"     =>  "gif|jpg|png",
                "max_size"          =>  '100',
                "max_width"         =>  '1024',
                "max_height"        =>  '768'
            ));
           
            if($this->upload->do_multi_upload("uploadfile")){
               
                $data['upload_data'] = $this->upload->get_multi_upload_data();
               
                echo '<p class = "bg-success">' . count($data['upload_data']) . 'File(s) successfully uploaded.</p>';
               
            } else {   
                // Output the errors
                $errors = array('error' => $this->upload->display_errors('<p class = "bg-danger">', '</p>'));              
           
                foreach($errors as $k => $error){
                    echo $error;
                }
               
            }
           
        } else {
            echo '<p class = "bg-danger">An error occured, please try again later.</p>';
           
        }
        // Exit to avoid further execution
        exit();
    }
}

Configure Routes

Go to application/config/routes.php and add the following lines:

1
2
3
$route['upload/do_upload'] = 'upload/do_upload';
$route['upload/(:any)'] = 'upload/view/$1';
$route['upload'] = 'upload';

The Upload Folder

You’ll need a destination folder for your uploaded images. Create a folder at the root of your CodeIgniter installation called uploads and set its file permissions to 777.

Go ahead and try it!

To try your form, visit your site using a URL similar to this one:

1
example.com/index.php/upload/

Implementing AJAX Pagination with Search in CodeIgnier

ajax-pagination-with-search-in-codeigniter

In this tutorial, you will learn how to program an Ajax pagination with search functionality. We will not be using any 3rd party libraries for PHP or JavaScript to accomplish this task so that I may pass along the highest level of programming education and insight on this topic to you.

You can just copy the code below and customize the database fields to meet your requirements. I have also provided a brief documentation within the codes so that the steps are clear.

Step 1

In your application/view, create a new folder and name it “blog”. Then inside the blog folder, create a new file and name it “index.php”. Open index.php, add the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<script type = "text/javascript" src = "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>

<article class="navbar-form navbar-left">
    <div class="form-group">
        <input type="text" class="form-control blog_search_text" placeholder="Enter a keyword">
    </div>
    <input type = "submit" value = "Search" class = "btn btn-primary blog_search_submit" />
</article>

<br />

<div class="col-md-12 content">
    <script type="text/javascript">
    jQuery(document).ready(function($) {

        function cvf_load_all_posts(page){
            // Start the transition
            $(".cvf_pag_loading").fadeIn().css('background','#ccc');
           
            // Data to receive from our controller
            var data = {
                page: page,
                search: $('.blog_search_text').val()
            };
           
            // Send the data
            $.post("<?php echo base_url('blog/index_display')?>", data, function(response) {
                // If successful Append the data into our html container
                $(".cvf_universal_container").html(response);
                // End the transition
                $(".cvf_pag_loading").css({'background':'none', 'transition':'all 1s ease-out'});
            });
        }
       
        // Load page 1 as the default
        cvf_load_all_posts(1);
       
        // Handle the clicks
        $('body').on('click', '.cvf_universal_container .cvf-universal-pagination li.active', function(){
            var page = $(this).attr('p');
            cvf_load_all_posts(page);
           
        });
       
        // Search
        $('body').on('click', '.blog_search_submit', function(){
            cvf_load_all_posts(1);
        });
                   
    });
    </script>
       
    <div class = "cvf_pag_loading">
        <div class = "cvf_universal_container">
            <div class="cvf-universal-content"></div>
        </div>
    </div>
</div>

In the above code, we created a script that will send a request post to the controller file “http://yourwebsite.com/blog/index_display”. Our request post contains the page number we want to be loaded and the value of the search input field. We then output the response of our controller to the div container with a class name: “cvf_universal_container”.

Step 2

In you application/controller, create a new file and name it “blog.php”, inside blog.php, add the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?php
class Blog extends CI_Controller {

    public function __construct() {
       
        parent::__construct();
       
    }

    public function index() {
       
        $data['post_title'] = 'Blog';
       
        $this->load->view('templates/header', $data);
        $this->load->view('pages/blog/index');
        $this->load->view('templates/footer');
       
    }
   
    public function index_display() {
       
        // $this->output->enable_profiler(TRUE);
       
        // Set default variables
        $msg = '';
       
        if($this->input->post('page')){
           
            $pag_container = '';
            $where = '';
           
            // Sanitize the received page  
            $page = $this->input->post('page');
            $cur_page = $page; 
            $page -= 1;
            // Set the number of results to display
            $per_page = 5;
            $previous_btn = true;
            $next_btn = true;
            $first_btn = true;
            $last_btn = true;
            $start = $page * $per_page;
           
            if(!empty($this->input->post('search'))){
                $where = ' AND (post_title LIKE "%%' . $this->input->post('search') . '%%" OR post_content LIKE "%%' . $this->input->post('search') . '%%") ';
            }
           
            // Set the table where we will be querying data
            $table_name = "ci_posts";
           
            // Query the necessary posts
            $all_blog_posts = $this->db->query("
                SELECT * FROM "
. $table_name . "
                WHERE post_type = 'post' AND post_status = 'publish'"
.$where."
                ORDER BY post_date DESC
                LIMIT ?, ?"
, array($start, $per_page) );
           
            // At the same time, count the number of queried posts
            $blogs_count = $this->db->query("
                SELECT COUNT(ID) as blog_count FROM "
. $table_name . "
                WHERE post_type = 'post' AND post_status = 'publish'"
);
           
            // Loop into all the posts
            foreach($all_blog_posts->result() as $key => $post):
               
                // Set the desired output into a variable
                $msg .= '
                <div class = "col-md-12">      
                    <h2><a href="'
. base_url('blog/' . $post->post_name) . '">' . $post->post_title . '</a></h2>
                    <p>'
. $post->post_excerpt . '</p>
                </div>'
;
               
            endforeach;
           
            // Optional, wrap the output into a container
            $msg = "<div class='cvf-universal-content'>" . $msg . "</div><br class = 'clear' />";
                   
            // This is where the magic happens
            $count = $blogs_count->row();
            $no_of_paginations = ceil($count->blog_count / $per_page);

            if ($cur_page >= 7) {
                $start_loop = $cur_page - 3;
                if ($no_of_paginations > $cur_page + 3)
                    $end_loop = $cur_page + 3;
                else if ($cur_page <= $no_of_paginations && $cur_page > $no_of_paginations - 6) {
                    $start_loop = $no_of_paginations - 6;
                    $end_loop = $no_of_paginations;
                } else {
                    $end_loop = $no_of_paginations;
                }
            } else {
                $start_loop = 1;
                if ($no_of_paginations > 7)
                    $end_loop = 7;
                else
                    $end_loop = $no_of_paginations;
            }
           
            // Pagination Buttons logic        
            $pag_container .= "
            <div class='cvf-universal-pagination'>
                <ul>"
;

            if ($first_btn && $cur_page > 1) {
                $pag_container .= "<li p='1' class='active'>First</li>";
            } else if ($first_btn) {
                $pag_container .= "<li p='1' class='inactive'>First</li>";
            }

            if ($previous_btn && $cur_page > 1) {
                $pre = $cur_page - 1;
                $pag_container .= "<li p='$pre' class='active'>Previous</li>";
            } else if ($previous_btn) {
                $pag_container .= "<li class='inactive'>Previous</li>";
            }
            for ($i = $start_loop; $i <= $end_loop; $i++) {

                if ($cur_page == $i)
                    $pag_container .= "<li p='$i' class = 'selected' >{$i}</li>";
                else
                    $pag_container .= "<li p='$i' class='active'>{$i}</li>";
            }
           
            if ($next_btn && $cur_page < $no_of_paginations) {
                $nex = $cur_page + 1;
                $pag_container .= "<li p='$nex' class='active'>Next</li>";
            } else if ($next_btn) {
                $pag_container .= "<li class='inactive'>Next</li>";
            }

            if ($last_btn && $cur_page < $no_of_paginations) {
                $pag_container .= "<li p='$no_of_paginations' class='active'>Last</li>";
            } else if ($last_btn) {
                $pag_container .= "<li p='$no_of_paginations' class='inactive'>Last</li>";
            }

            $pag_container = $pag_container . "
                </ul>
            </div>"
;
           
            // We echo the final output
            echo
            '<div class = "cvf-pagination-content">' . $msg . '</div>' .
            '<div class = "cvf-pagination-nav">' . $pag_container . '</div>';
           
        }  
   
    }

    public function view($post_name) {
   
       
        $data['blog'] = $this->post_model->get_post(array('post_name' => $post_name));

        if (!empty($data['blog'])) {
           
            $data['post_title'] = $data['blog']->post_title;
           
            $this->load->view('templates/header', $data);
            $this->load->view('pages/blog/view', $data);
            $this->load->view('templates/footer');
           
        } else {
            show_404();
        }
   
       
    }
}

Step 3

In your application/view, create another file and name it “view.php”, open view.php and add the following code:

1
2
<h1><?php echo $blog->post_title; ?></h1>
<p><?php echo autop($blog->post_content); ?></p>

The above code will display the contents of the clicked post.

Styling

If you need a quick styling for your pagination, you can add the following code into your css file:

1
2
3
4
5
6
.cvf_pag_loading {padding: 20px;}
.cvf-universal-pagination ul {margin: 0; padding: 0;}
.cvf-universal-pagination ul li {display: inline; margin: 3px; padding: 4px 8px; background: #FFF; color: black; }
.cvf-universal-pagination ul li.active:hover {cursor: pointer; background: #1E8CBE; color: white; }
.cvf-universal-pagination ul li.inactive {background: #7E7E7E;}
.cvf-universal-pagination ul li.selected {background: #1E8CBE; color: white;}

Now taste the AJAXified pagiantion in action. We have done a great job already.
If you have enjoyed this tutorial please do share with others. You know, sharing means caring :).

How to do Ajax in Codeigniter

Today we are going to discuss how you can integrate AJAX using jQuery’s Form Plugin in your CodeIgniter project.

When I first began developing for CodeIgniter, I was left scratching my head understanding methods that made the process easy and within CodeIgniter best practices. I find it strange that there is not much information about how to integrate AJAX into it, since it is a relatively known framework and AJAX methodology is very common in web development.

I have been looking for information about this subject on the Internet and the truth is that, besides being very scattered, it is not very clear, so here is my contribution from what I have learned, hopefully developers out there will find this tutorial useful.

Step 1

In your header template file, include the following scripts:

1
2
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>

Feel free to use other AJAX methods, but for this tutorial we are going to use the jQuery form plugin

Step 2

Let’s create a form where we will be doing AJAX
Create a view file named “add.php”, then add the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<h1>New Blog</h1>

<!-- This is where we will be outputting response from our AJAX requests -->
<div class = "new-blog-messages"></div>
<div class = "col-md-6">
        <!-- Generate the form attribute and add a class which we will be using to identify the form when we do AJAX -->
        <?php echo form_open('blog/add_submit', array('class' => 'new-blog-form')) ?>

        <div class = "form-group">
            <label for="title">Title</label>
            <input type="input" name="post_title" class = "form-control post_title" /><br />
        </div>
       
        <div class = "form-group">
            <label for="text">Description</label>
            <textarea name="post_content" class = "form-control post_content" rows = "15"></textarea><br />
        </div>
       
        <div class = "form-group">
            <label for="text">Short Description</label>
            <textarea name="post_excerpt" class = "form-control post_excerpt" rows = "7"></textarea><br />
        </div>
       
        <input type="submit" name="submit" value="Submit" class = "btn btn-primary new-blog-submit" />
    </form>
   
    <script>                   
    jQuery(document).ready(function($) {
       
        var options = {
            beforeSend: function(){
                $(".new-blog-messages").html('<p><img src = "<?php echo base_url() ?>images/loading.gif" class = "loader" /></p>');
            },
            complete: function(response){
                if(response.responseText === 'success'){
                    $(".new-blog-messages").html('<p class = "bg-success">Blog successfully created!</p>');
                } else {
                    $(".new-blog-messages").html('<p class = "bg-danger">' + response.responseText + '</p>');
                }
            }
        };     
        $(".new-blog-form").ajaxForm(options); 

        return false;
       
    });
    </script>
   
</div>

The above code shows the implementation of the ajax form plugin using the ajaxForm function:

1
$(".new-blog-form").ajaxForm(options);

The form is submitted to the action url: http://youwebsite.com/blog/add_submit, where the add_submit is the name of the method in your controller file found in step 3.

Step 3

Create a controller named “blog.php” then add the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?php
class Blog extends CI_Controller {

    public function __construct() {
       
        parent::__construct();
   
    }
   
    public function index() {
       
        $data['post_title'] = 'New Blog Item';

        // Load the add.php page
        $this->load->view('templates/header', $data);
        $this->load->view('pages/blog/add');
        $this->load->view('templates/footer');
       
    }
   
    public function add_submit() {
       
        $post_content = $this->input->post('post_content');
        $post_title = $this->input->post('post_title');
        $post_excerpt = $this->input->post('post_excerpt');

        // Validate input fields
        if(empty($post_title)){
            echo 'Title can not be empty';
           
        } else if(empty($post_content)) {
            echo 'Description can not be empty';
           
        } else {
        // Replace this area with your INSERT POST function
            $args = array(
                'post_content'      =>  $post_content,
                'post_title'        =>  $post_title,
                'post_excerpt'      =>  $post_excerpt
            );
           
            $post_id = $this->post_model->insert_post($args);
           
            if($post_id) {
                echo 'success';
               
            } else {
                echo 'Failed to create new blog, please try again later.';
               
            }
        }
       
        exit();
           
    }
}

Kudos on a job well done! You have learned and achieved seamless communication through Ajax. In many cases, the code to do so was quite small. Now, you might enjoy the challenge of further enhancing the application by implementing any other UI ideas that you may have had while reading this tutorial.

How to use LazyLoad.Js

I was recently working on a portfolio website that contains a lot of images, this kind of website usually takes longer to load since it has to complete rendering all page images from top to bottom. Lately I came across this plugin called “LazyLoad” which delays the loading of images in long web pages, the images outside of viewport are not loaded until user scrolls to them. Using this plugin will make the page load faster, it can also help to reduce server load.

Download Example

Lazy Load depends on jQuery. Include them both in your HTML code:

1
2
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js"></script>

To apply LazyLoad to the images, we need to define a unique class within the image tag which will be identified by the plugin and then hook it into the lazyload(); function.

1
$("img.lazy").lazyload({effect : "fadeIn"});

For the img tag, we are not going to use the “src” attribute, instead we are going to use a new attribute “data-original”. Also, make sure to include both width and height attributes because without them the plugin may not work or can cause undesirable behaviors.

1
<img class="lazy" data-original="images/1.jpg" width="640" height="480">

Complete code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js"></script>
<script>
$(function() {
    $("img.lazy").lazyload({effect : "fadeIn"});
});
</script>
</head>
<body>
    <div align = "center">
        <img class="lazy" data-original="images/1.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/2.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/3.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/4.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/5.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/6.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/7.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/8.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/9.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/10.jpg" width="640" height="480"><br />
        <img class="lazy" data-original="images/11.jpg" width="640" height="480">
    </div>
</body>
</html>

If you need to load images from another server, you can use AJAX via the jQuery function: load();

1
2
3
4
5
 $("#container").one("click", function() {
     $("#container").load("images.html", function(response, status, xhr) {
         $("img.lazy").lazyload();
     });              
 });

When checking the example, clear browser cache between each request. You can check what is actually loaded using your browser’s developer console (Chrome, Safari and IE) or FireBug (Firefox)

If you check your console, you will notice that the images that are NOT YET visible looks like this:

1
<img class="lazy" data-original="images/3.jpg" width="640" height="480" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC">

The “src” attribute doesn’t have the actual path, therefore it hasn’t been loaded yet.

Using LazyLoad with AJAX

To achieve this, we have to make sure that we execute LazyLoad only when the DOM elements have already been outputted to the screen, so it would make sense if we put our LazyLoad script after displaying the images on AJAX success.

1
2
3
4
5
6
7
8
9
10
$.post(ajax_url, data, function(response, textStatus, jqXHR) {
    if(textStatus == 'success'){
        // Display the images into the container
        $(".container").html($(response).fadeIn('slow'));
        // Execute LazyLoad
        $('.lazy').lazyload({
            effect: 'fadeIn'
        });
    }
});

Fall back for browsers that do not support JavaScript

It is always a good practice to enable default image to load when JavaScript is not supported by the browser.

1
2
<img class="lazy" src="images/example.jpg" data-original="img/example.jpg" width="100%" />
<noscript><img src="images/example.jpg" width="100%" /></noscript>

To prevent double copy of images from showing up, we should place the following CSS on our stylesheet file:

1
2
3
.lazy {
    display: none;
}

Ensuring that we initialize the images and would only show if JavaScript is enabled, we need to force the images to show up using the .show() function. Our code will now look like this:

1
2
3
$("img.lazy").show().lazyload({
    effect : "fadeIn"
});

AJAX using XMLHttpRequest Object

Bellow is a sample code that asynchronously sends a post request to a file named “test.php”. All of these happens behind the scenes using XMLHttpRequest Object.

So why use AJAX on the client-side instead of PHP? – AJAX allows web pages to be updated asynchronously by exchanging small amounts of data with the server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page. Classic web pages, (which do not use AJAX) reloads the entire page for the content to change, which, in my opinion, is slower. So that is why I prefer AJAX for client-side processing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html>
<head>
    <script>
    function cvf_load_php_response() {
        var xmlhttp;
        if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp = new XMLHttpRequest();
        } else { // code for IE6, IE5
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
       
        // Stores a function (or the name of a function) to be called automatically each time the readyState property changes
        xmlhttp.onreadystatechange=function() {
           
            // 0: request not initialized
            // 1: server connection established
            // 2: request received
            // 3: processing request
            // 4: request finished and response is ready
           
            // 200: "OK"
            // 404: Page not found
           
            // When readyState is 4 and status is 200, the response is ready:
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                document.getElementById("cvf_div").innerHTML = xmlhttp.responseText;
            }
        }
        xmlhttp.open("POST","test.php",true);
        // To POST data like an HTML form, add an HTTP header with setRequestHeader(). Specify the data you want to send in the send() method:
        xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xmlhttp.send("fname=Carlo&lname=Fontanos");
    }
   
   
    // Load the function or if you want trigger the function on button click then use onclick="cvf_load_php_response()"
    cvf_load_php_response();
    </script>
</head>
<body>
    <div id="cvf_div"></div>
</body>
</html>

What we did above is we instantiated the XMLHttpRequest (for IE7+, Firefox, Chrome, Opera, Safari) or ActiveXObject(“Microsoft.XMLHTTP”) – (for IE6, IE5) and set it into a variable xmlhttp. We then set a function onreadystatechange that will be called automatically each time the readyState property changes. If the readyState returns “4” with the status of “200”, we set the response of xmlhttp.responseText to the element where we want the response of “test.php” to be outputted.

Create a new php file “test.php” on the same folder then place this block of code:

1
2
3
4
5
6
7
<?php
// Check if post is set and not empty
if(isset($_POST['fname']) && !empty($_POST['fname'])) {
        // Generate the response
    echo 'I received this first name: ' . $_POST['fname'];
}
?>

if you want to trigger a $_GET to read contents of a document like a text file, then you don’t need to give the .send() method any parameters. There is also no need to set the setRequestHeader() for HTTP header.

1
2
xmlhttp.open("GET","test.txt",true);
xmlhttp.send();

Reference: www.w3schools.com

Example of an Ajaxified WordPress Admin using OOP Style

ajaxified-wordpress-admin-using-oop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
class Td_Admin {
   
    public function __construct() {
        add_action('admin_menu', array($this, 'cvf_td_register_site_options') );
        add_action('wp_ajax_cvf_td_update_trade_settings', array($this, 'cvf_td_update_trade_settings') );
        add_action('admin_enqueue_scripts', array($this, 'cvf_td_load_admin_scripts') );
    }
   
    public static function cvf_td_load_admin_scripts() {
   
        wp_enqueue_style( 'admin-css', get_template_directory_uri() . '/css/admin.css', false, "1.1.1", false);
    }

   
    public static function cvf_td_register_site_options() {
        add_submenu_page( 'edit.php?post_type=page', 'Settings', 'Settings', 'administrator', 'trade-settings', 'Td_Admin::cvf_td_trade_settings' );
    }
   
    public static function cvf_td_trade_settings(){
        ?>
        <h2>Wp Trade Settings</h2>
        <span class = "update-trade-settings-response td-response"></span>
        <table class="form-table">
            <tbody>
                <tr>
                    <th><label for="limit_repost">Items can be reposted after:</label></th>
                    <td><input type="text" name="limit_repost" id="limit_repost" value="<?php echo get_option('td_limit_repost'); ?>" placeholder = "" class="regular-text"> <span class="description">Specify in hours, Default is: 24</span></td>
                </tr>
                <tr>
                    <th><label for="max_image_upload">Maximum Image Upload</label></th>
                    <td><input type="text" name="max_image_upload" id="first_name" value="<?php echo get_option('td_max_image_upload'); ?>" class="regular-text"></td>
                </tr>
                <tr>
                    <th><label for="max_image_size">Maximum Image Size</label></th>
                    <td><input type="text" name="max_image_size" id="max_image_size" value="<?php echo get_option('td_max_image_size'); ?>" class="regular-text"><span class="description">Specify in kilobytes, Default is: 500</span></td>
                </tr>
                <tr>
                    <th><label for="currency_symbol">Currency Symbol</label></th>
                    <td>
                        <select name="currency_symbol" class = "currency_symbol">
                            <option value = "dollar">$ Dollar</option>
                            <option value = "euro">&euro; Euro</option>
                            <option value = "pound">&pound; Pound</option>
                            <option value = "yen">&yen; Yen</option>
                            <option value = "peso">&#8369; Peso</option>
                        </select>
                    </td>
                </tr>
                <tr>
                     <th><label for="currency_symbol">Editor</label></th>
                    <td>
                        <?php
                        $content = '';
                        $editor_id = 'mycustomeditor';
                        wp_editor( $content, $editor_id );
                        ?>
                    </td>
                </tr>
            </tbody>
        </table>
       
        <p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary update_wp_trade_settings" value="Update Settings"></p>
               
        <script type="text/javascript">
        jQuery(document).ready(function($) {
           
            var current_currency = '<?php echo get_option('td_currency_symbol'); ?>';
            if(current_currency){
                $(".currency_symbol").val(current_currency);
            }
           
            $('input').on('focus', function(){
                $('input').removeClass('border-red');
            });
           
            $("body").on("click", ".update_wp_trade_settings", function(e) {                        
                e.preventDefault();
               
                if(!$("input[name=limit_repost]").val()) {
                    $("input[name=limit_repost]").addClass('border-red');
                } else if(!$("input[name=max_image_upload]").val()) {
                    $("input[name=max_image_upload]").addClass('border-red');
                } else if(!$("input[name=max_image_size]").val()) {
                    $("input[name=max_image_size]").addClass('border-red');
                } else {
               
                    $(".update-trade-settings-response").html('<p><img src = "<?php bloginfo('template_url'); ?>/images/loading.gif" class = "loader" /></p>');
                    var data = {
                        'action': 'cvf_td_update_trade_settings',
                        'cvf_action': 'update_trade_settings',
                        'limit_repost': $("input[name=limit_repost]").val(),
                        'max_image_upload': $("input[name=max_image_upload]").val(),
                        'max_image_size': $("input[name=max_image_size]").val(),
                        'currency_symbol': $(".currency_symbol").val(),
                        'text_area_text': tinymce.editors.mycustomeditor.getContent()
                    };
                   
                    $.post(ajaxurl, data, function(response) {
                        element = $(".update-trade-settings-response");
                        $('html, body').animate({scrollTop: $(element).offset().top-100}, 150);
                        $(element).html(response);
                    });
                }
            });
        });
        </script>
        <?php
       
    }
   
    public static function cvf_td_update_trade_settings(){
       
        $errors = array();
        $currency_list = array('dollar', 'euro', 'pound', 'yen', 'peso');
       
        if(isset($_POST['cvf_action']) && $_POST['cvf_action'] == 'update_trade_settings'){
           
            foreach($_POST as $k => $value){
                $_POST[$k] = sanitize_text_field($value);
            }
           
            if (empty($errors) === true) {
           
                if(!is_numeric($_POST['limit_repost'])){
                    $errors[] = 'Only numeric values are allowed in "Items can be reposted after"';
                } elseif ($_POST['limit_repost'] < 0) {
                    $errors[] = 'Repost limit cannot be negative';
                }
               
                if(!is_numeric($_POST['max_image_upload'])){
                    $errors[] = 'Only numeric values are allowed in "Maximum Image Upload"';
                } elseif ($_POST['max_image_upload'] < 0) {
                    $errors[] = 'Maximum Image Upload cannot be negative';
                }
               
                if(!is_numeric($_POST['max_image_size'])){
                    $errors[] = 'Only numeric values are allowed in "Maximum Image Size"';
                } elseif ($_POST['max_image_size'] < 10) {
                    $errors[] = '"Maximum Image Upload" must be greater than 10kb';
                }
               
                if(!in_array($_POST['currency_symbol'], $currency_list)){
                    $errors[] = 'Invalid Currency Symbol.';
                }
            }
           
            if(empty($_POST) === false && empty($errors) === true) {
               
                update_option('td_limit_repost', $_POST['limit_repost']);
                update_option('td_max_image_upload', $_POST['max_image_upload']);
                update_option('td_max_image_size', $_POST['max_image_size']);
                update_option('td_currency_symbol', $_POST['currency_symbol']);
                update_option('td_text_area_text', $_POST['text_area_text']);
               
                echo '
                <div id="message" class="updated">
                    <p><strong>Settings updated.</strong></p>
                </div>'
;
               
            } elseif (empty($errors) === false) {
                echo '
                <div id="message" class="error">
                    <ul>'
;
                    foreach ($errors as $error) {
                        echo '<li><strong>' . $error . '</strong></li>';
                    }
                echo '</ul>
                </div>'
;
               
            }
        }
       
        exit();
    }
   
} new Td_Admin();

WordPress Frontend AJAX Pagination

ajax-pagination-wordpress-front-end

Demo

Tutorial

Step 1: Create a custom page in WordPress, if you do not know what a custom WordPress page is, read on this link: http://codex.wordpress.org/Template_Hierarchy

Step 2: Add this code into your custom page (Explanations are on the codes)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php get_header(); ?>

    <div class="col-md-12 content">
        <div class = "inner-box content no-right-margin darkviolet">
            <script type="text/javascript">
            jQuery(document).ready(function($) {
                // This is required for AJAX to work on our page
                var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
               
                function cvf_load_all_posts(page){
                    // Start the transition
                    $(".cvf_pag_loading").fadeIn().css('background','#ccc');
                   
                    // Data to receive from our server
                    // the value in 'action' is the key that will be identified by the 'wp_ajax_' hook
                    var data = {
                        page: page,
                        action: "demo-pagination-load-posts"
                    };
                   
                    // Send the data
                    $.post(ajaxurl, data, function(response) {
                        // If successful Append the data into our html container
                        $(".cvf_universal_container").html(response);
                        // End the transition
                        $(".cvf_pag_loading").css({'background':'none', 'transition':'all 1s ease-out'});
                    });
                }
               
                // Load page 1 as the default
                cvf_load_all_posts(1);
               
                // Handle the clicks
                $('.cvf_universal_container .cvf-universal-pagination li.active').live('click',function(){
                    var page = $(this).attr('p');
                    cvf_load_all_posts(page);
                   
                });
                           
            });
            </script>
            <div class = "cvf_pag_loading">
                <div class = "cvf_universal_container">
                    <div class="cvf-universal-content"></div>
                </div>
            </div>
           
        </div>     
    </div>
   
<?php get_footer(); ?>

We might have different page structures so feel free to edit the code.

Step 3: Add this block of code into your functions.php (Explanations are on the codes)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Receive the Request post that came from AJAX
add_action( 'wp_ajax_demo-pagination-load-posts', 'cvf_demo_pagination_load_posts' );
// We allow non-logged in users to access our pagination
add_action( 'wp_ajax_nopriv_demo-pagination-load-posts', 'cvf_demo_pagination_load_posts' );
function cvf_demo_pagination_load_posts() {
   
    global $wpdb;
    // Set default variables
    $msg = '';
   
    if(isset($_POST['page'])){
        // Sanitize the received page  
        $page = sanitize_text_field($_POST['page']);
        $cur_page = $page;
        $page -= 1;
        // Set the number of results to display
        $per_page = 5;
        $previous_btn = true;
        $next_btn = true;
        $first_btn = true;
        $last_btn = true;
        $start = $page * $per_page;
       
        // Set the table where we will be querying data
        $table_name = $wpdb->prefix . "posts";
       
        // Query the necessary posts
        $all_blog_posts = $wpdb->get_results($wpdb->prepare("
            SELECT * FROM "
. $table_name . " WHERE post_type = 'post' AND post_status = 'publish' ORDER BY post_date DESC LIMIT %d, %d", $start, $per_page ) );
       
        // At the same time, count the number of queried posts
        $count = $wpdb->get_var($wpdb->prepare("
            SELECT COUNT(ID) FROM "
. $table_name . " WHERE post_type = 'post' AND post_status = 'publish'", array() ) );
       
        /**
         * Use WP_Query:
         *
        $all_blog_posts = new WP_Query(
            array(
                'post_type'         => 'post',
                'post_status '      => 'publish',
                'orderby'           => 'post_date',
                'order'             => 'DESC',
                'posts_per_page'    => $per_page,
                'offset'            => $start
            )
        );
           
        $count = new WP_Query(
            array(
                'post_type'         => 'post',
                'post_status '      => 'publish',
                'posts_per_page'    => -1
            )
        );
        */

       
        // Loop into all the posts
        foreach($all_blog_posts as $key => $post):
           
            // Set the desired output into a variable
            $msg .= '
            <div class = "col-md-12">      
                <h2><a href="'
. get_permalink($post->ID) . '">' . $post->post_title . '</a></h2>
                <p>'
. $post->post_excerpt . '</p>
            </div>'
;
           
        endforeach;
       
        // Optional, wrap the output into a container
        $msg = "<div class='cvf-universal-content'>" . $msg . "</div><br class = 'clear' />";
       
        // This is where the magic happens
        $no_of_paginations = ceil($count / $per_page);

        if ($cur_page >= 7) {
            $start_loop = $cur_page - 3;
            if ($no_of_paginations > $cur_page + 3)
                $end_loop = $cur_page + 3;
            else if ($cur_page <= $no_of_paginations && $cur_page > $no_of_paginations - 6) {
                $start_loop = $no_of_paginations - 6;
                $end_loop = $no_of_paginations;
            } else {
                $end_loop = $no_of_paginations;
            }
        } else {
            $start_loop = 1;
            if ($no_of_paginations > 7)
                $end_loop = 7;
            else
                $end_loop = $no_of_paginations;
        }
       
        // Pagination Buttons logic    
        $pag_container .= "
        <div class='cvf-universal-pagination'>
            <ul>"
;

        if ($first_btn && $cur_page > 1) {
            $pag_container .= "<li p='1' class='active'>First</li>";
        } else if ($first_btn) {
            $pag_container .= "<li p='1' class='inactive'>First</li>";
        }

        if ($previous_btn && $cur_page > 1) {
            $pre = $cur_page - 1;
            $pag_container .= "<li p='$pre' class='active'>Previous</li>";
        } else if ($previous_btn) {
            $pag_container .= "<li class='inactive'>Previous</li>";
        }
        for ($i = $start_loop; $i <= $end_loop; $i++) {

            if ($cur_page == $i)
                $pag_container .= "<li p='$i' class = 'selected' >{$i}</li>";
            else
                $pag_container .= "<li p='$i' class='active'>{$i}</li>";
        }
       
        if ($next_btn && $cur_page < $no_of_paginations) {
            $nex = $cur_page + 1;
            $pag_container .= "<li p='$nex' class='active'>Next</li>";
        } else if ($next_btn) {
            $pag_container .= "<li class='inactive'>Next</li>";
        }

        if ($last_btn && $cur_page < $no_of_paginations) {
            $pag_container .= "<li p='$no_of_paginations' class='active'>Last</li>";
        } else if ($last_btn) {
            $pag_container .= "<li p='$no_of_paginations' class='inactive'>Last</li>";
        }

        $pag_container = $pag_container . "
            </ul>
        </div>"
;
       
        // We echo the final output
        echo
        '<div class = "cvf-pagination-content">' . $msg . '</div>' .
        '<div class = "cvf-pagination-nav">' . $pag_container . '</div>';
       
    }
    // Always exit to avoid further execution
    exit();
}

You can add some styling to your pagination by appending this block of CSS code into your style.css

1
2
3
4
5
6
.cvf_pag_loading {padding: 20px;}
.cvf-universal-pagination ul {margin: 0; padding: 0;}
.cvf-universal-pagination ul li {display: inline; margin: 3px; padding: 4px 8px; background: #FFF; color: black; }
.cvf-universal-pagination ul li.active:hover {cursor: pointer; background: #1E8CBE; color: white; }
.cvf-universal-pagination ul li.inactive {background: #7E7E7E;}
.cvf-universal-pagination ul li.selected {background: #1E8CBE; color: white;}

Now you can start using this as your base AJAX Pagination structure to implement more sophisticated logics.

Implementing AJAX in WordPress

Ajax1

There are plenty of sources on the Web that cover this topic, when I first began developing for WordPress I was left scratching my head understanding methods that made the process easy and within WordPress best practices. Finally I came up with the most simpliest and standard way of implementing AJAX in WordPress.

NOTE: This article assumes you have a good understanding of jQuery and AJAX (and of course, PHP)

Using Ajax on the Administration Side

Since WordPress 2.8, ajaxurl is always defined in the admin header and points to admin-ajax.php

Here’s a short example. All this will be in one file. First, add some javascript that will trigger the AJAX request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript" >
jQuery(document).ready(function($) {
   
     // the value of 'action' is the key that will be identified by the 'wp_ajax_' hook
    var data = {
        'action': 'my_action',
        'message': 123
    };
   
    // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
    $.post(ajaxurl, data, function(response) {
        // Output the response which should be 'Hellow World'
        alert(response);
    });
});
</script>

Then, set up a PHP function that will handle the request:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
add_action( 'wp_ajax_my_action', 'my_action_callback' );
function my_action_callback() {
    // Check if set and if the received value is 123
    if (isset($_POST['message']) && $_POST['message'] == 123 ) {
        echo 'Hello World';
    }
    // Always exit to avoid further execution
    exit();
   
}
?>

Using Ajax on the Front-end Side

By default, the wp_ajax_ displays the output only to logged-in users, if you want it to fire on the front-end for both visitors and logged-in users, simply add this additional hook into your action handler:

1
add_action( 'wp_ajax_nopriv_my_action', 'my_action_callback' );

Unlike on the admin side, the ajaxurl javascript global does not get automatically defined for you, a quick fix for this is to create a variable which contains the admin-ajax.php

1
2
3
4
5
var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
$.post(ajaxurl, data, function(response) {
    // Output the response which should be 'Hellow World'
    alert(response);
});

Error Return Values

If the Ajax request fails in wp-admin/admin-ajax.php, the response will be -1 or 0, depending on the reason for the failure. Additionally, if the request succeeds, but the Ajax action does not match a WordPress hook defined with add_action(‘wp_ajax_(action)’, …) or add_action(‘wp_ajax_nopriv_(action)’, …), then admin-ajax.php will respond 0