FLASH SALE Get 20% OFF everything using the coupon code: FLASH20 View WordPress Plugins →

WordPress Tutorials

on in Blog
Last modified on

Our WordPress tutorials allow you to extend the power of WordPress. Our step by step WordPress tutorials are easy to understand and follow the WordPress best practices. These WordPress tutorials contain real-life examples, tips, and hacks that allow you to learn WordPress faster.

More tutorials and snippets: JavaScriptjQuery

How to track your WordPress theme usage

Warning: This code snippet does not include the mandatory opt-in for usage tracking. Please add it to your theme’s settings. Note the usage of get_option('usage_sent') to only send the request once.

For this tutorial, you will need several small functions inside your theme and a database and a tracker on your server.

Include these functions in your theme:

<?php
add_action('init', 'usageEt');

function getUsageUserIp() {
    $ip = '';
    $sources = [
       'REMOTE_ADDR',
       'HTTP_X_FORWARDED_FOR',
       'HTTP_CLIENT_IP'
    ];

    foreach ($sources as $source) {
        if (isset($_SERVER[$source])) {
            $ip = $_SERVER[$source];
        } else if (getenv($source)) {
            $ip = getenv($source);
        }
    }

    return $ip;
}

function usageEt() {
    // If usage data has been sent, return
    if ((int) get_option('usage_sent') === 0) {
        global $wpdb, $wp_version;

        $yourTheme = wp_get_theme();
        $yourName = (string) $yourTheme->get('Name');
        $yourVersion = (string) $yourTheme->get('Version');

        $data = [
            'type' => 'theme',
            'name' => $yourName,
            'url' => get_site_url(),
            'version' => $yourVersion,
            'php_version' => PHP_VERSION,
            'sql_version' => $wpdb->db_version(),
            'wp_version' => $wp_version,
            'ip' => getUsageUserIp(),
            'server' => $_SERVER['SERVER_SOFTWARE'],
            'memory_limit' => WP_MEMORY_LIMIT,
            'admin_email' => get_option('admin_email')
        ];

        $c = curl_init();
        curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($c, CURLOPT_TIMEOUT, 15);
        curl_setopt($c, CURLOPT_URL, 'https://example.com/analytics/tracker.php');
        curl_setopt($c, CURLOPT_POST, sizeof($data));
        curl_setopt($c, CURLOPT_POSTFIELDS, $data);

        $response = curl_exec($c);
        $info = curl_getinfo($c);
        curl_close($c);

        add_option('usage_sent', 1, '', 'yes');
    }
}

On your server, you need the tracker and a database.

Here’s the tracker:

<?php
define('DBHOST', 'your-database-host');
define('DBUSER', 'your-database-user');
define('DBPASS', 'your-database-pass');
define('DBNAME', 'db_usage');

function nuukDb() {
    $nuukDb = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME . ';charset=utf8', DBUSER, DBPASS);
    $nuukDb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $nuukDb->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    return $nuukDb;
}

$data = $_POST['data'];

$type = $_POST['type'];
$name = $_POST['name'];
$url = $_POST['url'];
$version = $_POST['version'];
$php = $_POST['php_version'];
$sql = $_POST['sql_version'];
$wp = $_POST['wp_version'];
$ip = $_POST['ip'];
$server = $_POST['server'];
$memory = $_POST['memory_limit'];
$email = $_POST['admin_email'];

// this code will prepare and execute a query
$nuuk = nuukDb()->prepare("INSERT INTO wp_usage_data (
    type, name, url, version, php_version, sql_version, wp_version, ip, server, memory_limit, admin_email
) VALUES (
    '$type', '$name', '$url', '$version', '$php', '$sql', '$wp', '$ip', '$server', '$memory', '$email')");
$nuuk->execute();

echo 'success';

Check the database structure below:

--
-- Database: `db_usage`
--

-- --------------------------------------------------------

--
-- Table structure for table `wp_usage_data`
--

CREATE TABLE `wp_usage_data` (
    `id` int(11) NOT NULL,
    `type` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '''theme'' or ''plugin''',
    `name` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
    `url` text COLLATE utf8mb4_unicode_ci NOT NULL,
    `version` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
    `php_version` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
    `sql_version` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
    `wp_version` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
    `ip` text COLLATE utf8mb4_unicode_ci NOT NULL,
    `server` text COLLATE utf8mb4_unicode_ci NOT NULL,
    `memory_limit` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
    `admin_email` text COLLATE utf8mb4_unicode_ci NOT NULL,
    `date_submitted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `wp_usage_data`
--
ALTER TABLE `wp_usage_data` ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `wp_usage_data`
--
ALTER TABLE `wp_usage_data` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

That’s it. Enjoy!

WordPress plugin usage data

I am fiddling with the idea to capture WordPress plugin usage data. Instead of using GET or POST requests, I thought of asynchronously sending an AJAX request once.

The $('#element') will most likely contain a switch to inform the plugin that data has been sent. This switch may reset every 3 or 6 months, in case the hosting provider updates their software.

if ((window.location.href.indexOf('imagepress_admin_page') > -1) && ($('#element').length > 0)) {
    let phpVersion = $('.php-version').text(),
        mysqlVersion = $('.mysql-version').text(),
        wpVersion = $('.wp-version').text(),
        siteUri = window.location.href;

    $.ajax({
        url: "https://mysite.com/web/report.php",
        type: "POST",
        data: JSON.stringify({
            phpVersion: phpVersion,
            mysqlVersion: mysqlVersion,
            wpVersion: wpVersion,
            siteUri: siteUri
        }),
        dataType: "json",
        success: function (response) {
        },
        error: function (response) {
        }
    });
}

Note that the code is just the initial idea, it doesn’t actually extract the data using PHP or an API. I am still considering it, and I am testing it with one free plugin to measure the client load and server impact.

How to display a list of WordPress plugins from the official repository

Note: This function has been updated to use one transient only. Scroll down to see the updated version.

This code will retrieve a list of plugins from the WordPress plugin repository and it will cache the results for 24 hours, using the plugin API. Use the {wordpress-items slugs="quick-event-calendar, youtube-playlist-player, wp-perfect-plugin, mobilize, ecards-lite, marketplace-items"} shortcode to display them. Note that some CSS styling might be necessary.

<?php
/*
 * WordPress Plugins Shortcode
 * 
 * Displays your WordPress plugins inside a post or a page
 * 
 * @author Ciprian Popescu
 * @copyright 2016-2020 Ciprian Popescu
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */

function whiskey_wordpress_items($atts) {
    extract(shortcode_atts(array(
        'slugs' => '',
    ), $atts));

    $url = 'https://api.wordpress.org/plugins/info/1.0/';

    $data = '';

    $slugs = explode(',', $slugs);
    $slugCount = count($slugs);
    if ($slugCount > 0) {
        $data .= '<ul class="columnar">';
        for ($i = 0; $i < $slugCount; $i++) {
            $args = (object) ['slug' => trim($slugs[$i])];
            $request = ['action' => 'plugin_information', 'timeout' => 15, 'request' => serialize($args)];

            /*
             * Set plugin data transient if it does not exist.
             * If it exists, retrieve it from the database
             */
            $slug_transient = get_transient('wp-plugin-' . strtolower(trim($slugs[$i])));

            if($slug_transient === false) {
                $response = wp_remote_post($url, ['body' => $request]);
                $plugin_info = unserialize($response['body']);

                $slug = $plugin_info->slug;
                $name = $plugin_info->name;
                $downloaded = $plugin_info->downloaded;
                $author = $plugin_info->author;
                $version = $plugin_info->version;

                set_transient (
                    'wp-plugin-' . strtolower(trim($slugs[$i])),
                    $slug . '|' . $name . '|' . $downloaded . '|' . $author . '|' . $version,
                    24 * HOUR_IN_SECONDS
                );
            } else {
                $plugin_info = explode('|', $slug_transient);

                $slug = $plugin_info[0];
                $name = $plugin_info[1];
                $downloaded = $plugin_info[2];
                $author = $plugin_info[3];
                $version = $plugin_info[4];
            }
            //

            $data .= '<li>
                <div class="package-widget package-wordpress">
                    <div class="package-details">
                        <h3><a class="name" href="https://wordpress.org/plugins/' . $slug . '/">' . $name . '</a></h3>
                        <p class="description"><code>' . $version . '</code></p>
                        <p class="author quiet">downloaded ' . number_format($downloaded) . ' times | ' . $author . '</p>
                    </div>
                </div>
            </li>';
        }
        $data .= '</ul>';
    }

    return $data;
}

add_shortcode('wordpress-items', 'whiskey_wordpress_items');

This is how it looks on my website:

WordPress Plugins - API

UPDATE #1

I have updated the code to use one transient instead of multiple ones, based on the number of plugins. See the updated code below. It will safely replace the one above.

function whiskey_wordpress_items($atts) {
    extract(shortcode_atts([
        'slugs' => ''
    ], $atts));

    $data = get_transient('whiskey_plugins');
    if ($data === false) {
        $url = 'https://api.wordpress.org/plugins/info/1.0/';

        $data = '';

        $slugs = explode(',', $slugs);
        $slugCount = count($slugs);
        if ($slugCount > 0) {
            $data .= '<ul class="columnar">';
                for ($i = 0; $i < $slugCount; $i++) {
                    $args = (object) array('slug' => trim($slugs[$i]));
                    $request = ['action' => 'plugin_information', 'timeout' => 15, 'request' => serialize($args)];

                    $response = wp_remote_post($url, ['body' => $request]);

                    $plugin_info = unserialize($response['body']);

                    $slug = $plugin_info->slug;
                    $name = $plugin_info->name;
                    $downloaded = $plugin_info->downloaded;
                    $author = $plugin_info->author;
                    $version = $plugin_info->version;

                    $data .= '<li>
                        <div class="package-widget package-wordpress">
                            <div class="package-details">
                                <h3><a class="name" href="https://wordpress.org/plugins/' . $slug . '/">' . $name . '</a></h3>
                                <p class="description"><code>' . $version . '</code></p>
                                <p class="author quiet">downloaded ' . number_format($downloaded) . ' times | ' . $author . '</p>
                            </div>
                        </div>
                    </li>';
                }
            $data .= '</ul>';
        }

        set_transient('whiskey_plugins', $data, 24 * HOUR_IN_SECONDS);
    }

    return $data;
}

UPDATE #2

I have been using the WordPress plugin API on my homepage to get my WordPress repository plugins and live data about the number of downloads. Everything was live and the API was really fast, but the page still seemed sluggish. So I have implemented transients and the speed increased by 59.54% on the homepage and by 23.91% on the dedicated plugins page.

Transients and page speed

How to add pagination to custom WordPress tables

First of all, we need to write a class to handle pagination. Second, we need to display the pagination in our custom WordPress table (in the back-end section, for a plugin or for theme settings).

Here is the pagination class and here below is the sample usage:

include 'classes/Pagination.php';

<?php
$items = $wpdb->get_results("SELECT field1, field2, field3 FROM wp_custom_table");
$items = $wpdb->num_rows;

if ($items > 0) {
    $p = new Pagination;
    $p->items($items);
    $p->target('admin.php?page=mypage');
    $p->calculate();

    if (!isset($_GET['paging'])) {
        $p->page = 1;
    } else {
        $p->page = (int) $_GET['paging'];
    }

    $limit = 'LIMIT ' . ($p->page - 1) * $p->limit . ', ' . $p->limit;
} else {
    echo '<p>No records found!</p>';
}

$results = $wpdb->get_results("SELECT field1, field2, field3 FROM wp_custom_table $limit", ARRAY_A);
?>
<div class="tablenav"><?php echo $p->show(); ?></div>
<table class="wp-list-table widefat striped posts">
    <thead>
        <tr>
            <th scope="col">Field 1</th>
            <th scope="col">Field 2</th>
            <th scope="col">Field 2</th>
        </tr>
    </thead>
    <?php
    foreach($results as $row) {
        echo '<tr>';
            echo '<td>' . $row['field1'] . '</td>';
            echo '<td>' . $row['field2'] . '</td>';
            echo '<td>' . $row['field3'] . '</td>';
        echo '</tr>';
    }
    ?>
</table>

And that is all. The pagination class is compatible with WordPress 4.7+.

How to add custom columns to custom post types

Here’s how to add additional custom columns to any post type in WordPress. This applies to the admin editing screen. Note that I am using ACF in the example below, but you can easily switch get_field() with get_post_meta($post->ID, 'key_name', true). Also, I am using event as the post type slug.

function gb1475228224_page_columns($columns) {
    $columns = array(
        'cb'    => '<input type="checkbox">',
        'title' => 'Title',
        'date'  => 'Date',
        'cdate' => 'Event Date',
        'ctime' => 'Event Time',
    );

    return $columns;
}

function gb1475228224_custom_columns($column) {
    global $post;

    if($column == 'thumbnail') {
        echo wp_get_attachment_image( get_field('page_image', $post->ID), array(200,200) );
    } else if($column == 'cdate') {
        echo 'Event Date:<br>' . get_field('booking_date', $post->ID);
    } else if($column == 'ctime') {
        echo 'Event Time:<br>' . get_field('booking_time', $post->ID);
    }
}

add_action("manage_posts_custom_column", "gb1475228224_custom_columns");
add_filter("manage_edit-event_columns", "gb1475228224_page_columns");

That is all. Enjoy.

How to create a taxonomy dropdown

Create a taxonomy dropdown and hide empty terms:

<select class="filter-categories">
    <option value="">Category...</option>
    <?php
    $terms = get_terms([
        'taxonomy' => 'event-category',
        'hide_empty' => true
    ]);
    if (!empty($terms) && !is_wp_error($terms)) {
        foreach ($terms as $term) {
            echo '<option value="' . $term->slug . '">' . $term->name . ' (' . $term->count . ')</option>';
        }
    }
    ?>
</select>

Modify the event-category taxonomy based on your requirements.

How to generate an expandable archive list

WordPress Archives

WordPress can generate a yearly archive or a monthly archive. But not both. The code below uses a filter and a small jQuery code to create an expandable/collapsible archive list.

Here’s the archive filter:

/*
 * Add filter to query archives by year
 */
function whiskey_getarchives_filter($where, $args) {
    if(isset($args['year'])) {
        $where .= ' AND YEAR(post_date) = ' . intval($args['year']);
    }

    return $where;
}

add_filter('getarchives_where', 'whiskey_getarchives_filter', 10, 2);

Here’s the archive display code:

<dl class="tree-accordion">
    <?php
    $currentyear = date("Y");
    $years = range($currentyear, 1950); // Set the starting year
    foreach ($years as $year) { ?>
        <dt><a href=""><i class="fa fa-fw fa-plus-square-o" aria-hidden="true"></i> <?php echo $year; ?></a></dt>
        <?php
        $archive = wp_get_archives('echo=0&show_post_count=1&type=monthly&year=' . $year);
        $archive = explode('</li>', $archive);
        $links = [];

        foreach($archive as $link) {
            $link = str_replace(['<li>', "\n", "\t", "\s"], '' , $link);
            if ('' != $link) {
                $links[] = $link;
            } else {
                continue;
            }
        }

        $fliplinks = array_reverse($links);
        if (!empty($fliplinks)) {
            echo '<dd>';
                foreach ($fliplinks as $link) {
                    echo '<span>' . $link . '</span>';
                }
            echo '</dd>';
        } else {
            echo '<dd class="tree-accordion-empty"></dd>';
        }
        ?>
    <?php } ?>
</dl>

Here’s the jQuery code:

jQuery(document).ready(function () {
    var allPanels = jQuery('.tree-accordion > dd').hide();

    jQuery('.tree-accordion > dt > a').click(function () {
        $target = jQuery(this).parent().next();

        if (!$target.hasClass('active')) {
            allPanels.removeClass('active').slideUp();
            $target.addClass('active').slideDown(100);
        }

        return false;
    });

    jQuery('.tree-accordion-empty').prev().hide();
});

And, finally, here’s the CSS code:

.tree-accordion {
    line-height: 1.5;
}
.tree-accordion dt, .tree-accordion dd {}
.tree-accordion dt a {
    display: block;
}
.tree-accordion .fa {
    color: #666666;
}
.tree-accordion dd a {}
.tree-accordion dd span {
    display: block;
}
.tree-accordion dd {
    margin: 0 0 0 20px;
}

Note that I’m using FontAwesome for the plus icon.

WordPress performance tutorial: How to cache your mega menu

Navigation menus in WordPress are not performing very well in case of lots of submenus, sections, multilevel items or the well-known mega-menus. Here’s a function that allows you to cache the output of your navigation menu.

Prerequisites:

  1. WordPress Lighthouse plugin
  2. A modern WordPress theme using wp_nav_menu() function

Usage:

In order for this tutorial to work, activate the Lighthouse plugin and replace wp_nav_menu() with lhf_nav_menu() in your header.php and footer.php templates. All the other parameters stay the same. See sample usage below.

<?php
if (function_exists('lhf_nav_menu')) {
    lhf_nav_menu(array('theme_location' => 'primary', 'menu_class' => '', 'container' => 'div', 'container_class' => ''));
} else {
    wp_nav_menu(array('theme_location' => 'primary', 'menu_class' => '', 'container' => 'div', 'container_class' => ''));
}

Enjoy your faster menu!

WordPress numbered siblings (child page navigation)

The other day, I had to create a numbered navigation section for child pages. The parent page would hold 15 child pages which needed to be navigated through using a previous/next system and have the current index displayed (i.e. 3/15).

The previous/next arrows use FontAwesome and the index is styles using CSS. The GitHub code doesn’t style the navigation in any way. Use CSS or modify the second function (numbered_navigation()) in order to achieve a similar result.

How to rename all WordPress attachments to lowercase

I have recently had a situation on my hands, where attached PDFs had names like My-Document.pdf, and my-document.pdf would not work. While waiting for hosting support to fix it by activating the mod_speling module, here’s what I did:

First, I created a PHP file, called _renamer.php, and added this code:

<?php
$directory = 'wp-content/uploads/2014/02';

echo '<div>starting...</div>';

$files = scandir($directory);

foreach ($files as $key => $name) {
    $oldName = $name;
    $newName = strtolower($name);
    echo '<div>checking... ';
    rename("$directory/$oldName", "$directory/$newName");
    echo '' . $directory/$oldName . ' renamed to ' . $directory/$newName . '</div>';
}

The code above would rename all the files in the selected directory to lowercase. I only needed to change the directory path several times for each directory. Then, I ran mydomain.eu/_renamer.php.

After the above operation was complete for all selected directories, I needed to update the post links and the post metas. The following SQL queries, run inside phpMyAdmin, will finish the process.

UPDATE wp_posts SET `guid` = LOWER(`guid`) WHERE post_type = 'attachment';
UPDATE wp_postmeta SET `meta_value` = LOWER(`meta_value`) WHERE meta_key = '_wp_attached_file';

Don’t forget to clear the cache, if using any plugin or CDN, and you’re done!

WordPress video submission – A case study and a code snippet

You have often wondered how to create a small form and allow users to submit/upload videos on your WordPress based website. To be honest, this module allows the user to upload any file format, such as archives, documents, audio files or graphic files.

I will not be using a custom post format for this module, as the case study is based on a real life example. All video submissions will go into a separate category called “Submissions” and details will be submitted as post content.

The entire code consists of a main function – videowizard_main() – which adds the form engine to the page. It also processes the form, combines all form information and uploads the attachment. The post gets published in a special category, called “Submissions” (which can be changed to any name for that matter, just change the ID – in this case 3), as draft/private, so only an administrator can see it and publish it or further process it.

The videodjin_ functions and actions allow the posts listing to show the attached files in a separate column.

Finally, the add_shortcode('videowizard', 'videowizard_main') function creates a shortcode which can be placed on any post or page, like this [videowizard].

For brevity (and speed) purposes, I have placed this chunk of code at the end of the functions.php file. It can also be placed in a drop-in plugin. The form has no options, but it can be modified/amended/customized directly from the main function.

Show page content inside another page

Gist is available here.

<?php
function my_show_page($atts) {
    extract(shortcode_atts(['page_id' => 0], $atts));
    $page = get_page($page_id);

    return apply_filters('the_content', $page->post_content);
}

add_shortcode('my_show_page', 'my_show_page');

// [my_show_page page_id="999"]

Show category posts in another page

Gist is available here.

<?php
function pp_custom_content($atts) {
    extract(shortcode_atts([
        'type' => '',
        'cat' => ''
    ], $atts));
    $am_display = '';
    $loop = new WP_Query(['post_type' => $type, 'posts_per_page' => 10, 'category_name' => $cat]);
    while ($loop->have_posts()) : $loop->the_post();
        $am_display .= '<div style="float: left; width: 47%; margin-right: 16px; height: 200px; overflow: hidden;">';
        $am_display .= '<div style="float: left; margin-right: 8px;"><a href="' . get_permalink() . '">' . get_the_post_thumbnail(get_the_ID(), 'thumbnail') . '</a></div>';
        $am_display .= '<div><strong>' . get_the_title() . '</strong> (<a href="' . get_permalink() . '">Details</a>)<br>' . get_the_excerpt() . '</div>';
        $am_display .= '</div>';
    endwhile;
    $am_display .= '<br clear="all">';
    $am_display .= '<hr>';

    return $am_display;
}

// usage: [pp type="post" cat="category"]
add_shortcode('pp', 'pp_custom_content'); // shortcode, function

How to add a custom post type to your WordPress site

I had to create a custom post type for 2 clients, coincidentally testimonials. The code is pretty simple and straightforward and can be reused by changing post type and name. The code below illustrates the registration of a custom post type with 2 hierarchical taxonomies and one non-hierarchical taxonomy.

Gist is available here.

How to create a tabbed interface for your WordPress plugin

Have you ever wanted to create a tabbed interface for your plugin? Have you ever wanted to rearrange your plugin’s options and provide tabs instead of subpages and submenus? In the following tutorial, I’ll show you how to create a simple plugin with multiple tabs.

We’ll start with the usual page structure:

<div class="wrap">
    <h2>Sample Plugin</h2>

    <?php
    $active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'sample_tab_1';
    if (isset($_GET['tab'])) {
        $active_tab = $_GET['tab'];
    }
    ?>
    <h2 class="nav-tab-wrapper">
        <a href="?page=sample&amp;tab=sample_tab_1" class="nav-tab <?php echo $active_tab == 'sample_tab_1' ? 'nav-tab-active' : ''; ?>"><?php _e('Sample Tab 1', 'sample'); ?></a>
        <a href="?page=sample&amp;tab=sample_tab_2" class="nav-tab <?php echo $active_tab == 'sample_tab_2' ? 'nav-tab-active' : ''; ?>"><?php _e('Sample Tab 2', 'sample'); ?></a>
        <a href="?page=sample&amp;tab=sample_tab_3" class="nav-tab <?php echo $active_tab == 'sample_tab_3' ? 'nav-tab-active' : ''; ?>"><?php _e('Sample Tab 3', 'sample'); ?></a>
        <a href="?page=sample&amp;tab=sample_tab_4" class="nav-tab <?php echo $active_tab == 'sample_tab_4' ? 'nav-tab-active' : ''; ?>"><?php _e('Sample Tab 4', 'sample'); ?></a>
        <a href="?page=sample&amp;tab=sample_tab_5" class="nav-tab <?php echo $active_tab == 'sample_tab_5' ? 'nav-tab-active' : ''; ?>"><?php _e('Sample Tab 5', 'sample'); ?></a>
    </h2>

Notice the bolded code is where active tab checking is performed. That’s where the magic happens.

We’ll then add the tabs:

<?php if ($active_tab == 'sample_tab_1') { ?>
    <div id="poststuff" class="ui-sortable meta-box-sortables">
        <div class="postbox">
            <h3><?php _e('Sample Settings', 'sample'); ?></h3>
            <div class="inside">
                <p><?php _e('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'sample'); ?></p>
            </div>
        </div>
    </div>
<?php } else if ($active_tab == 'sample_tab_2') { ?>
    <div id="poststuff" class="ui-sortable meta-box-sortables">
        <div class="postbox">
            <h3><?php _e('Sample Settings', 'sample'); ?></h3>
            <div class="inside">
                <p><?php _e('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', 'sample'); ?></p>
            </div>
        </div>
    </div>
<?php } else if ($active_tab == 'sample_tab_3') { ?>

And so on. Notice you can add how many tabs you want.

You close the function by ending the current loop and the main div.

<?php } ?>
</div>

Enjoy!

WordPress popular posts without plugins

I’ve been working on tweaking some themes, and I decided to remove all widgets and hardcode content boxes straight into the sidebar template file. So, here’s how to add a box with most popular (commented) posts:

<div>
    <h2>Popular Content:</h2>
    <div>
        <ul>
            <?php
            $result = $wpdb->get_results("SELECT comment_count, ID, post_title FROM $wpdb->posts ORDER BY comment_count DESC LIMIT 0, 8");
            foreach ($result as $post) {
                setup_postdata($post);
                $postId = $post->ID;
                $title = $post->post_title;
                $commentCount = $post->comment_count;
                if ((int) $commentCount !== 0) { ?>
                    <li><a href="<?php echo get_permalink($postId); ?>" title="<?php echo $title; ?>"><?php echo $title; ?></a></li>
                <?php }
            } ?>
        </ul>
    </div>
</div>

That’s it!

WordPress most commented articles during past years

As the end of the year is getting closer and closer, you might want to show a top ten most commented articles. By modifying the code, you could display a top 3, top 15, top 100, or whatever number you like.

Here’s how:

<h2>Most commented articles in 2009</h2>
<ul>
    <?php
    $result = $wpdb->get_results("SELECT comment_count, ID, post_title, post_date FROM $wpdb->posts WHERE post_date BETWEEN '2009-01-01' AND '2009-12-31' ORDER BY comment_count DESC LIMIT 0, 10");
    foreach ($result as $topTen) {
        $postId = $topTen->ID;
        $title = $topTen->post_title;
        $commentCount = $topTen->comment_count;
        if ((int) $commentCount !== 0) {
            ?>
            <li><a href="<?php echo get_permalink($postId); ?>"><?php echo $title; ?></a></li>
        <?php }
    } ?>
</ul>

That’s it!

How to change post author ID for security purposes

Do you know how certain security plugins advise against having a user with ID 1? Hacking a WordPress site involves other methods but if you are really determined (slash paranoid) to change it, try either of these options:

1. Run these queries in phpMyAdmin:

UPDATE wp_posts SET post_author='1000' WHERE post_author='1';
UPDATE wp_users SET ID = '1000' WHERE ID = '1';
UPDATE wp_usermeta SET user_id = '1000' WHERE user_id = '1';

ALTER TABLE wp_users AUTO_INCREMENT = 1001;

2. Or create a new administrator user, then place this function in your functions.php file:

<?php wp_delete_user($id, $reassign); ?>

Make sure you replace the $id variable with 1 and the $reassign variable with the new user ID, the one you’ve just created. The function will remove the user with ID 1 and assign all posts and pages (including media and custom post types) to the new user. Remove the line from functions.php after running it. Remember to backup your WordPress database before running the queries.

Related posts