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.
Table of Contents
- How to track your WordPress theme usage
- WordPress plugin usage data
- How to display a list of WordPress plugins from the official repository
- How to add pagination to custom WordPress tables
- How to add custom columns to custom post types
- How to create a taxonomy dropdown
- WordPress performance tutorial: How to cache your mega menu
- WordPress numbered siblings (child page navigation)
- How to rename all WordPress attachments to lowercase
- WordPress video submission – A case study and a code snippet
- Show page content inside another page
- Show category posts in another page
- How to add a custom post type to your WordPress site
- How to Create a Tabbed Interface for Your WordPress Plugin
- WordPress Popular Posts Without Plugins
- WordPress Most Commented Articles During Past Years
- How to Change the Default WordPress Admin User ID for Security Purposes
More JavaScript tutorials and snippets
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:

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.

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.
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:
- WordPress Lighthouse plugin
- 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><?php esc_html_e( 'Sample Plugin', 'sample' ); ?></h2>
<?php
// Sanitize and set active tab
$active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'sample_tab_1';
?>
<h2 class="nav-tab-wrapper">
<a href="?page=sample&tab=sample_tab_1"
class="nav-tab <?php echo $active_tab === 'sample_tab_1' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'Sample Tab 1', 'sample' ); ?>
</a>
<a href="?page=sample&tab=sample_tab_2"
class="nav-tab <?php echo $active_tab === 'sample_tab_2' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'Sample Tab 2', 'sample' ); ?>
</a>
<a href="?page=sample&tab=sample_tab_3"
class="nav-tab <?php echo $active_tab === 'sample_tab_3' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'Sample Tab 3', 'sample' ); ?>
</a>
<a href="?page=sample&tab=sample_tab_4"
class="nav-tab <?php echo $active_tab === 'sample_tab_4' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'Sample Tab 4', 'sample' ); ?>
</a>
<a href="?page=sample&tab=sample_tab_5"
class="nav-tab <?php echo $active_tab === 'sample_tab_5' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_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 esc_html_e( 'Sample Settings', 'sample' ); ?></h3>
<div class="inside">
<p><?php esc_html_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.', 'sample' ); ?></p>
</div>
</div>
</div>
<?php } elseif ( $active_tab === 'sample_tab_2' ) { ?>
<div id="poststuff" class="ui-sortable meta-box-sortables">
<div class="postbox">
<h3><?php esc_html_e( 'Sample Settings', 'sample' ); ?></h3>
<div class="inside">
<p><?php esc_html_e( 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.', 'sample' ); ?></p>
</div>
</div>
</div>
<?php } elseif ( $active_tab === 'sample_tab_3' ) { ?>
<div id="poststuff" class="ui-sortable meta-box-sortables">
<div class="postbox">
<h3><?php esc_html_e( 'Sample Settings', 'sample' ); ?></h3>
<div class="inside">
<p><?php esc_html_e( 'Add as many tabs as you need. Each section can hold settings, descriptions, or custom forms.', 'sample' ); ?></p>
</div>
</div>
</div>
<?php } ?>
</div>
And that’s it. You can add as many tabs as you like, and each tab can have its own settings, descriptions, or forms.
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. Here’s how to add a box with the most popular (commented) posts:
<div>
<h2>Popular Content:</h2>
<div>
<ul>
<?php
global $wpdb;
// Number of posts to show
$limit = 8;
// Prepare SQL query safely
$query = $wpdb->prepare(
"SELECT comment_count, ID, post_title
FROM {$wpdb->posts}
WHERE post_type = 'post'
AND post_status = 'publish'
ORDER BY comment_count DESC
LIMIT %d",
$limit
);
$results = $wpdb->get_results( $query );
if ( $results ) {
foreach ( $results as $post ) {
if ( (int) $post->comment_count !== 0 ) {
?>
<li>
<a href="<?php echo esc_url( get_permalink( $post->ID ) ); ?>"
title="<?php echo esc_attr( $post->post_title ); ?>">
<?php echo esc_html( $post->post_title ); ?>
</a>
(<?php echo intval( $post->comment_count ); ?>)
</li>
<?php
}
}
}
?>
</ul>
</div>
</div>
That’s it!
WordPress Most Commented Articles During Past Years
As the end of the year gets closer, you might want to display a Top 10 most commented articles. With a little code tweak, you can easily show a Top 3, Top 15, Top 100, or any number you like.
Here’s how:
<h2>Most Commented Articles in 2024</h2>
<ul>
<?php
global $wpdb;
// Define your year
$year = 2024;
// Prepare SQL query safely
$query = $wpdb->prepare(
"SELECT comment_count, ID, post_title, post_date
FROM {$wpdb->posts}
WHERE post_type = 'post'
AND post_status = 'publish'
AND post_date BETWEEN %s AND %s
ORDER BY comment_count DESC
LIMIT 0, 10",
$year . '-01-01 00:00:00',
$year . '-12-31 23:59:59'
);
$results = $wpdb->get_results( $query );
if ( $results ) {
foreach ( $results as $post ) {
if ( (int) $post->comment_count !== 0 ) {
?>
<li>
<a href="<?php echo esc_url( get_permalink( $post->ID ) ); ?>">
<?php echo esc_html( $post->post_title ); ?>
</a> (<?php echo intval( $post->comment_count ); ?>)
</li>
<?php
}
}
}
?>
</ul>
That’s it!
How to Change the Default WordPress Admin User ID for Security Purposes
Some security guides recommend avoiding a user account with the ID 1
because it’s predictable and often belongs to the first administrator created during installation. While WordPress itself is reasonably secure, changing or removing the default admin account can add an extra layer of protection – especially if you want to reduce brute-force login attempts.
Below are two safe approaches. Always back up your WordPress database before making changes.
Option 1: Update IDs Directly in the Database
If you prefer working with phpMyAdmin or another MySQL client, you can update the default user’s ID. Replace 1000
with the new ID you want to assign.
-- Reassign all posts authored by user ID 1 to user ID 1000
UPDATE wp_posts SET post_author = 1000 WHERE post_author = 1;
-- Change the user ID
UPDATE wp_users SET ID = 1000 WHERE ID = 1;
-- Update all user meta entries
UPDATE wp_usermeta SET user_id = 1000 WHERE user_id = 1;
-- Reset the AUTO_INCREMENT value so future users don’t conflict
ALTER TABLE wp_users AUTO_INCREMENT = 1001;
Option 2: Create a New Administrator and Reassign Content
The safer, WordPress-native way is to create a new administrator account via the dashboard, then delete the old one and reassign its content.
You can automate this once using the following function. Add it temporarily to your theme’s functions.php file or a small plugin:
<?php
/**
* Delete user ID 1 and reassign content.
*/
function myplugin_reassign_admin_user() {
$old_user_id = 1; // The user ID you want to delete
$new_user_id = 1000; // The new administrator ID
if ( user_can( $new_user_id, 'administrator' ) ) {
require_once ABSPATH . 'wp-admin/includes/user.php';
wp_delete_user( $old_user_id, $new_user_id );
}
}
add_action( 'init', 'myplugin_reassign_admin_user' );
After refreshing your site once (so the function runs), remove this code immediately to avoid repeated executions.