Navigate to the first character after the quote/double-quote and type the following in Vim:
di"
This is useful if you have something like the following:
{
"title": "Vim: How to Delete Text Enclosed In Quotes",
"permalink": "vim-how-to-delete-text-enclosed-in-quotes",
"published": "2023-08-12 14:00",
"categoryIDs": "5,5:0,5:1,5:5",
"description": "In Vim, 'di\"' is the one to use for deleting text in quotes.",
"thumbnail": "",
"smallimage": "",
"largeimage": ""
}
So, to navigate to the first character that starts with a double-quote, simply type /"e;
and the insertion point will highlight the double-quote. To get to the next double-quote, press the
n key again until you get to the one you want. After that, press
the l key to move to the first character and type the following:
di"
The output will be as follows:
{
"title": "",
"permalink": "vim-how-to-delete-text-enclosed-in-quotes",
"published": "2023-08-12 14:00",
"categoryIDs": "5,5:0,5:1,5:5",
"description": "In Vim, 'di\"' is the one to use for deleting text in quotes.",
"thumbnail": "",
"smallimage": "",
"largeimage": ""
}
And now, you can type whatever you want by pressing the i key on your keyboard.
Press the ESC (escape) key to get out of INSERT mode and back into
normal mode. To save changes and quit the Vim text editor, type :wq.
Bonus: If you have delimiters with quotes while writing the code such as:
"This is some \"quote\"!"
Vim will automatically delete the delimiters with quotes along with them, so performing
di" will delete everything that is in between quotes.
""
And you do not need to be inside quotes in order to delete inside the quotes! How cool is that?
*grinning face*
Oh, and you can also use the "change inside" sequence as well:
ci"
This puts you into INSERT mode so you can type text inside quotes.
Audience
This is for Linux users experienced in using the Vim text editor. Vim users should already know
the basics such as :q! for quitting the text editor without saving changes,
:wq for saving changes and quitting the text editor, i for going into
INSERT mode and use the ESC (escape) key to get back into normal
mode. All keyboard commands are beyond the scope of this short article that I wrote.
Conclusion
Hopefully this keyboard command can be of help to you. If you are a Linux user, please give
Vim a try.
This article is for experienced Linux users who are familar with environment variables such as
$HOME and $USER. These are the Linux users who are familiar with the
command line.
Problem and Solution
Here is an example not to use /home/$USER:
[gpeddie-games@epcotcenter ~]$ su - gpadmin
Password:
mkdir: cannot create directory ‘/home/gpadmin’: Permission denied
touch: cannot touch '/home/gpadmin/Templates/Text file': No such file or directory
mkdir: cannot create directory ‘/home/gpadmin’: Permission denied
-bash: /home/gpadmin/.local/share/DaVinciResolve/configs/.version: No such file or directory
Welcome. All activities monitored at all times.
Unauthorized access is strictly prohibited.
gpadmin@epcotcenter
~
$
And here's the script (/etc/profile) that illustrates an example:
# fix gnome missing 'New file' option
if [ ! -f /home/$USER/Templates/"Text file" ]
then
mkdir -p /home/$USER/Templates
touch /home/$USER/Templates/"Text file"
fi
# ...
# this is a hack to bypass the Davinci Resolve new install Welcome/Onboarding screen since it does not render properly and is not required.
if [ ! -f /home/$USER/.local/share/DaVinciResolve/configs/.version ];then
mkdir -p /home/$USER/.local/share/DaVinciResolve/configs/
echo "Onboarding.Version=10" > /home/$USER/.local/share/DaVinciResolve/configs/.version
fi
To fix this issue, simply replace all instances of /home/$USER with $HOME.
I am familiar with a text editor called Vim. It's a program that runs inside a terminal, similar to the
Command Prompt or PowerShell in Windows.
Before we proceed any further, let's create a backup copy of /etc/profile:
sudo cp /etc/profile /etc/profile.bak
If anything goes wrong, you now have a backup. You can simply use the cp (copy) command to
restore from the backup. Now let's begin.
First, open the Terminal (Konsole in KDE).
As root (or with sudo privileges), type the following command:
sudo vim /etc/profile
Type in the following command, starting with a colon:
:%s/\/home\/$USER/$HOME/g
The syntax for search and replace in Vim is as follows:
:%s/search/replace/g
Let's not concern ourselves with g at the end for now. Basically this command replaces
"search" with the next text "replace." In other words, we want to replace /home/$USER with
$HOME.
Let's have a look at the script again:
# fix gnome missing 'New file' option
if [ ! -f $HOME/Templates/"Text file" ]
then
mkdir -p $HOME/Templates
touch $HOME/Templates/"Text file"
fi
# ...
# this is a hack to bypass the Davinci Resolve new install Welcome/Onboarding screen since it does not render properly and is not required.
if [ ! -f $HOME/.local/share/DaVinciResolve/configs/.version ];then
mkdir -p $HOME/.local/share/DaVinciResolve/configs/
echo "Onboarding.Version=10" > $HOME/.local/share/DaVinciResolve/configs/.version
fi
So why would we want to replace /home/$USER with $HOME? That
/home/$USER should still work!
Let's look at the output again after we save the changes.
Save the changes to the /etc/profile file.
:wq
A : begins a command. w writes changes to the file and q
quits Vim
If you don't want to make changes to the file, then all you have to do is type :q! to
exit without saving any changes.
As I mentioned, let's look at the output again when I log into my administrator account from a user
account.
[gpeddie-games@epcotcenter ~]$ su - gpadmin
Password:
mkdir: cannot create directory ‘/home/gpadmin’: Permission denied
touch: cannot touch '/home/gpadmin/Templates/Text file': No such file or directory
mkdir: cannot create directory ‘/home/gpadmin’: Permission denied
-bash: /home/gpadmin/.local/share/DaVinciResolve/configs/.version: No such file or directory
Welcome. All activities monitored at all times.
Unauthorized access is strictly prohibited.
gpadmin@epcotcenter
~
$
Now, let's see the new output when I log back in as an administrator.
[gpeddie-games@epcotcenter ~]$ su - gpadmin
Password:
Last login: Sat Mar 18 11:13:52 EDT 2023 on pts/0
Welcome. All activities monitored at all times.
Unauthorized access is strictly prohibited.
gpadmin@epcotcenter
~
$
You have an Active Directory server running in a Windows Server virtual machine. You installed
Nobara so that you can do content creation and play games. You
wanted to join your Linux desktop to a Windows Active Directory in your home network (or a homelab, if you
want to call it). This is how you install the needed packages for Nobara 36 (that's what I am running)
so that you can join your Linux desktop to the Windows domain:
Replace yourlocaldomainname.lan with your local domain name and do the same for
youradminusername.
So when you log into your administrator account that's part of the Domain Administrators so that you can
gain sudo privileges, you might be wondering why you are getting strange output. Here it is again.
[gpeddie-games@epcotcenter ~]$ su - gpadmin
Password:
mkdir: cannot create directory ‘/home/gpadmin’: Permission denied
touch: cannot touch '/home/gpadmin/Templates/Text file': No such file or directory
mkdir: cannot create directory ‘/home/gpadmin’: Permission denied
-bash: /home/gpadmin/.local/share/DaVinciResolve/configs/.version: No such file or directory
Welcome. All activities monitored at all times.
Unauthorized access is strictly prohibited.
gpadmin@epcotcenter
~
$
If you look at the /etc/profile script that Linux executes when you log into your Linux account, you
will notice that the developer of Nobara assumed that your home directory is /home/gpadmin
and not /home/graysonpeddie.lan/gpadmin.
This is how I configure the System Security Services Daemon (SSSD, for short) which allows Linux users
to log into the Windows domain from the Linux desktop. Please note that only root can read
/etc/sssd/sssd.conf.
Let's ignore the entire file and focus in the fallback_homedir. The %d is
for the domain name that I logged into and the %u is for the username. In my case, since
I logged into my Linux desktop as gpeddie-games (that's my account designed only for
gaming), my full path is /home/graysonpeddie.lan/gpeddie-games and not
/home/gpeddie-games.
I have all my users (only me) in a separate home folder in order to prevent any kind of conflict with
local user accounts, but then I still append my local admin account with -local in order
to prevent any kind of conflicts in my Linux desktop machine.
Conclusion
This is why you should never assume that all users will be in the parent folder of the home directory.
The only use-case for using a $USER environment variable is if you need to get the name of
the user. Referring back to the /etc/profile script, here is an example:
if [ -x /usr/bin/id ]; then
if [ -z "$EUID" ]; then
# ksh workaround
EUID=`/usr/bin/id -u`
UID=`/usr/bin/id -ru`
fi
USER="`/usr/bin/id -un`"
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"
fi
After reading the script, I'm not sure why $LOGNAME and $MAIL exists in
that profile. Plus, I checked to see if I can get the name of the $USER in my VPS server
and there is already a $USER in the list of environment variables even though it's not
listed in /etc/profile. Strange...
Anyway, I hope I can be of help and use to the people within the Linux community and I am hoping that
people can learn from mistakes when getting the user's current home directory.
Article published: 2023-03-18 15:37
Categories: The World of Computers, Computers, Information Technology, Scripting and Programming
This is for anyone who currently host their WordPress or ClassicPress in a virtual private server such as DigitalOcean, Linode, or any other VPS providers. Any Linux user with knowledge of command line can perform backups and restoration tasks. You must be familiar with Linux and you know how to connect to your production server via SSH.
Plus, this article assumes that you have installed and configured WordPress in your VPS server. In addition, this article assumes you can perform basic database administration tasks such as adding a new database along with creating a new user for WordPress or ClassicPress. If your hosting provider provides managed WordPress or ClassicPress hosting, then this article may not apply to you. And because this article is for those who currently run a VPS server, I am going to have to assume that you have some hands-on experience with the Linux command line. This article need not apply to non-technical Linux, Mac, and Windows users. When I say non-technical Linux users, I'm talking about those who wanted to get away from Windows or Mac and simply wanted to use Linux just to browse the Internet and not deal with the command line.
Last, but not least, I am also going to assume that you know how to configure your Apache server as well. Both Apache and NGINX (pronounced Engine-X) configurations won't be covered here, including backing up and copying certificates that you get from your hosting provider.
You have your own VPS server that is running ClassicPress. Your domain name is exmaple.com and your SSH port number is (insert your TCP port number here). You have a development server for developing your own custom ClassicPress theme and you want to use your development server to backup everything from your production server.
Open the terminal and connect to your development server via SSH.
ssh yourusername@devserver -p (your port number if it's other than port 22)
From your development server, create an SSH key pair. We are going to use id_rsa.
ssh-keygen -t id_rsa
Next, enter the location and filename. Example:
/home/yourusername/.ssh/classicpress
After that, leave the passphrase blank. Press Enter a couple of times until you get back to the prompt ending with $.
Execute ssh-copy-id with the name of the public key file and specify the username and domain name.
ssh-copy-id -p (your TCP port number if not 22) -i ~/.ssh/classicpress.pub yourname@example.com
You should be able to login to your server. Give it a try.
ssh -p (your port number or remove -p) -i ~/.ssh/classicpress yourname@example.com
If all goes well, you should be able to connect to your production server without been prompted for the password or passphrase. I mentioned "without passphrase" because if a Linux user executes a single script for performing a backup and has set a passphrase for the SSH identity key, then the script will prompt a Linux user for the passphrase multiple times.
For the purpose of backing up a database, this task will take you through creating a .my.cnf file. This is a hidden file that will contain the username and password for mysqldump command. mysqldump allows a database administrator to backup the MySQL or MariaDB database.
Login to your production server from your development or backup server and perform the steps below.
Create a new file using either vim or nano called .my.cnf. This file will be saved in your home directory. mysqldump will read the file containing the username and password. For me, I use vim.
vim .my.cnf
If you are using Vim, press the i key to begin the INSERT mode and begin typing the following lines. If you are using nano, simply start typing the following.
Replace yourdatabaseusername with your database username and yourdatabasepassword with your database password. When installing either WordPress or ClassicPress on a VPS server, a Linux administrator must have created a database along with the username and set password during the installation process.
Save your changes.
For Vim users, exit out of INSERT mode by pressing the ESC key; then, type :wq to write changes to the .my.cjnf file and quit Vim. The : key begins the command for Vim, w saves the file, and q quits Vim. If you want to not write any changes and quit Vim, then the command is :q!. If the ! were omitted, then Vim will tell you that you need to save your changes before you quit Vim.
For nano users, the keyboard commands for saving the changes and quitting the text editor is CTRL+O for saving changes (press the ENTER key to confirm changes) and CTRL+X to quit the text editor.
Once done, do a database backup of your WordPress or ClassicPress database.
mysqldump ClassicPress > test.sql
This assumes that your database name is ClassicPress. Replace ClassicPress and enter the name of the database that you created when you installed WordPress or ClassicPress in your VPS server.
Your new file called test.sql should be in the same directory that you executed the command for testing. If you open that file up with your chosen editor, you should see all the database commands. Go ahead and close the file.
Log out of your production server by typing exit and press ENTER.
If your database backup is successful, congratulations! That task is done! Your may delete the test.sql file by using the rm command (be careful with that rm command; you might delete files accidentally). The benefit of having a .my.cnf file within the home directory is that you do not want to expose your database password when executing mysqldump. Let's use sleep 10 as an example as the mysqldump command can be very quick once executed.
If you have a Linux machine, open up two terminals and place them side by side.
For the first terminal, execute the following command:
watch 'ps aux | grep sleep'
The watch command will output the ps aux | grep sleep command. Here is the output of the command:
The command sleep 30 will be there for 30 seconds and will disappear from the watch output after the number of seconds have passed.
Use the CTRL+C key to exit out of the watch output. If you are using a Mac, the keyboard command is Control+C. Command+C is for copying text.
My point is, if the mysqldump command gets executed for a long period of time while dumping the entire database, mysqldump can show up in the list of processes. For example, let's say you executed a mysqldump command as follows:
This command will take about 30 seconds when dumping an entire MySQL/MariaDB database. As a result, the output will be as follows (note that this is just an example):
This can be a big problem if an attacker gains access to your server and monitors for the list of processes. That's why it's important to avoid storing passwords in a script whenever possible. That's where .my.cnf configuration file comes in. I did not know about this until I found out about adding a username and password in .my.cnf file. I learn something new almost every single day.
And if you want an example of a real process list, here it is with Apache web server running in my production server:
Okay. That's all for the remote server configuration. Let's get into some real fun part, the configuration of the development server for performing automated backups!
Development or Backup Server
Now here is the script you have all bee waiting for.
#!/bin/sh
# DIRP: Directory path
DIRP=~/cpbackup
# FILE: Partial file name
FILE=$DIRP/classicpress-$(date +%Y%m%d)
# Hostname, IP address, or domain name
HOST=example.com
# Private key for automated logging into an SSH server (no passphrase or password)
PKEY=~/.ssh/classicpress
# TCP Port number (use whatever port you assigned for an SSH server in the
# production server.)
PORT=22
# User name assigned in the remote Linux server
USER=yourusername
# Let's perform some checks. Does the directory in the $DIRP variable exist?
if [ ! -d $DIRP ]
then
echo "Directory not found: $DIRP"
exit 1
fi
# Does the SSH key pair exist?
if [ ! -f $PKEY -a ! -f $PKEY.pub ]
then
echo "SSH key pair $PKEY and $PKEY.pub does not exist. Exiting."
exit 1
fi
# Delete any backup files older than x number of days
find $DIRP -maxdepth 0 -mtime +10 -exec rm {} \;
# Backup the SQL database and store them locally for later restoration.
ssh -p $PORT $USER@$HOST -i $PKEY mysqldump ClassicPress > $FILE.sql
# Next, change directory to /var/www and compress them to standard output
# which then gets redirected to a compressed .tar.gz file.
ssh -p $PORT $USER@$HOST -i $PKEY 'cd /var/www && tar czf - *' > $FILE.tar.gz
# If there is a wp-config.php file stored outside /var/www, make a backup of
# that configuration file as well.
scp -P $PORT -i $PKEY $USER@$HOST:/var/wp-config.php $FILE-wp-config.php
# After that, backup the Apache virtual host configuration file.
scp -P $PORT -i $PKEY \
$USER@$HOST:/etc/apache2/sites-available/000-default.conf $FILE-apache.conf
# The script ran successfully.
exit 0
First, I recommend that you create a bin directory inside your home directory.
mkdir ~/bin
Then, use a text editor in the terminal of your choice (vim, nano, pico, etc.) to create a new file called cpbackup.sh. That script will be in the bin directory. In my case:
vim bin/cpbackup.sh
Copy the script that I created above. It's after the section called Development or Backup Server. The script starts with #!/bin/sh which is the start of the script. Copy it all the way down to exit 0.
Paste the script in the terminal. For Linux users who use a GNOME Terminal like I do, it's CTRL+SHIFT+V. For Mac users who use a Terminal, it's Command+V.
Make some changes to the variables, such as the host name/IP address, port number, et cetera.
Save your changes and exit the text editor.
Give the script an executable permission.
chmod +x bin/cpbackup.sh
chmod, called change mode, allows you to modify read, write, and execute permissions for a user, group, and others. This is beyond the scope of my article. Remember back in the Audience and Prerequisites section that I have to assume you are familiar with Linux. I will have to write another article if I have to get everyone up to speed on how to gain familiar with Linux.
After that, execute the following command:
bin/cpbackup.sh
And you are done! If all goes well, all of your backup files have been stored in the backup directory. And oh, be sure you test your backups by extracting all the WordPress/ClassicPress files from the archive and put it in /var/www. Restoring the database is as simple as:
mysql -u ClassicPress -p ClassicPress < classicpress.sql
Then, simply copy wp-config.php file to /var (it's a good idea to move your wp-config.php file outside of /var/www directory) and copy the Apache configuration file to /etc/apache2/sites-available/, enable the virtual host using the a2ensite command, and you are good to go.
To automatically backup your WordPress/ClassicPress site from time to time, simply execute crontab -e and enter at the bottom of the crontab file:
0 0 * * * bin/whateveryournameofthefileis.sh
And that is done.
Summary
Hopefully you should have a backup infrastructure in place so that if anything goes wrong, you can be able to restore from a good working backup. I hope my article is helpful to anyone who needs to perform a backup of their website including the database. Stay safe and practice good security hygiene online. Oh, and backup your files in your computer to a server or a NAS if you have one. And yes, you should definitely have a home server or a NAS for backing up all your important files. Thank you for reading my article.
Article published: 2022-11-17 08:47
Categories: The World of Computers, Information Technology, Internet, Networking, Scripting and Programming
As a web developer of my website, I have implemented pagination that allows anyone to view more posts by page and be able to view blog posts by month and year. I created a custom theme from scratch so that I can personalize my website to my liking. I wanted to give the pagination system an "electronic" look.
This screenshot shows pagination implemented in my website. In my development machine, I have set the number of posts per page to 5 in order to demonstrate the effect. I blurred the surrounding image to cut the file size by half.
For those with eyesight, you can click in the image to see a full screen of my desktop that shows the pagination system in effect.
if ( 'monthly' == $r['type'] ) {
$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`,"
." count(ID) as posts FROM $wpdb->posts $join $where"
." GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date $order $limit";
$key = md5( $query );
$key = "wp_get_archives:$key:$last_changed";
if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
$results = $wpdb->get_results( $query );
wp_cache_set( $key, $results, 'posts' );
}
if ( $results ) {
$after = $r['after'];
foreach ( (array) $results as $result ) {
$url = get_month_link( $result->year, $result->month );
/* translators: 1: month name, 2: 4-digit year */
$text = sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $result->month ), $result->year );
if ( $r['show_post_count'] ) {
$r['after'] = ' (' . $result->posts . ')' . $after;
}
$output .= get_archives_link( $url, $text, $r['format'], $r['before'], $r['after'] );
}
}
}
So I looked over the code and I saw that there is a $result variable that is converted into an array. I took that code from the WordPress.org website and I modified the code to suit my needs in functions.php inside my custom theme folder.
function monthly_archive_array() {
global $wpdb;
$r['type'] = 'monthly';
$where = apply_filters( 'getarchives_where',
"WHERE post_type = 'post' AND post_status = 'publish'", $r );
$last_changed = wp_cache_get( 'last_changed', 'posts' );
if ( ! $last_changed ) {
$last_changed = microtime();
wp_cache_set( 'last_changed', $last_changed, 'posts' );
}
/**
* Filter the SQL JOIN clause for retrieving archives.
*
* @since 2.2.0
*
* @param string $sql_join Portion of SQL query containing JOIN clause.
* @param array $r An array of default arguments.
*/
$join = apply_filters( 'getarchives_join', '', $r );
$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date ASC";
$key = md5( $query );
$key = "wp_get_archives:$key:$last_changed";
if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
$results = $wpdb->get_results( $query );
wp_cache_set( $key, $results, 'posts' );
}
if ( $results ) {
return (array)$results;
}
}
$archiveMonthlyList = monthly_archive_array();
function get_monthly_archive_array() {
global $archiveMonthlyList;
return $archiveMonthlyList;
}
Note that in the last 6 lines of code, I decided to have a function (get_monthly_archive_array()) get the result from a variable ($archiveMonthlyList). When I go to my website, ClassicPress executes a functions.php file in my custom theme folder so that I don't get the data from the database twice. Yet I actually do have wp_get_archives() in my sidebar, so I did have my website execute the same SQL statement twice. Well, one is in descending order from the newest to the oldest in the sidebar and I wanted to get the month and year of all the published posts from oldest to newest. If I replace the built-in function in my sidebar with my own function which exposes an array, I should be able to improve performance for my website, although probably not by much.
function constructLinkFromYearMonth($array, $index, $nextMonth) {
$offset = ($nextMonth === true) ? 1 : -1;
$spanlsaquote = ($offset === -1) ? "<span class='visualonly'>‹ </span>" : "";
$spanrsaquote = ($offset === 1) ? "<span class='visualonly'> ›</span>" : "";
$prevNextMonth = ($offset === -1) ? "Previous" : "Next";
echo "<a href='".get_month_link($array[$index + $offset]->year,$array[$index + $offset]->month )
."'>".$spanlsaquote."<span class='screenreader'>".$prevNextMonth." month: </span><span class='narrow-screen'>"
.showMonthYearLocale(
[$array[$index + $offset]->year,$array[$index + $offset]->month])."</span>".$spanrsaquote."</a>";
}
function show_pagination() {
global $paged;
if(empty($paged)) $paged = 1;
global $wp_query;
$pages = $wp_query->max_num_pages;
if(!$pages)
{
$pages = 1;
}
echo "<div class='pagination'>";
echo "<h3>View More Posts By Month or Page</h3>";
echo "<div class='pagination_area'>";
echo "<div class='pagination_top'>";
// Get the list of months and years from the archive in an array.
$monthlyArchive = get_monthly_archive_array();
// If there is year/month in URL, get it and trim the leading and
// trailing slashes. Example: 2021/04
$currentMonthYear = trim($_SERVER['REQUEST_URI'],'/');
// array[0] = year, array[1] = month
// Example: array[0] = "2021", array[1] = "04"
$curMonthYearArray = explode('/',$currentMonthYear);
if(preg_match("/^[0-9]{4}\/(0[1-9]|1[0-2])$/",$curMonthYearArray[0].'/'.$curMonthYearArray[1])) {
// array[0] = year, array[1] = month
// Example: array[0] = "2021", array[1] = "04"
$curMonthYearArray = explode('/',$currentMonthYear);
// Initialize a blank array for integers.
$intCurMonthYearArray = Array();
// Convert strings to integers in an array in a new variable.
foreach($curMonthYearArray as $curMonthYear)
$intCurMonthYearArray[] = (int)$curMonthYear;
// Initialize the integer for the index.
$indexOfMonthYearArray = 0;
foreach ($monthlyArchive as $key => $val) {
if ((int)$val->year === $intCurMonthYearArray[0] &&
(int)$val->month === $intCurMonthYearArray[1]) {
$indexOfMonthYearArray = $key;
}
}
echo "<ul class='pagination_month'>";
echo "<li class='month_current'>";
echo "<span>".showMonthYearLocale($curMonthYearArray)."</span>";
echo "</li>";
if($indexOfMonthYearArray > 0) {
echo "<li class='month_prev'>";
constructLinkFromYearMonth($monthlyArchive, $indexOfMonthYearArray, false);
echo "</li>";
} else echo "<li class='month_prev smallfontsize'><a class='screenreader'>Beginning of current month</a></li>";
if($indexOfMonthYearArray + 1 < count($monthlyArchive)) {
echo "<li class='month_next'>";
constructLinkFromYearMonth($monthlyArchive, $indexOfMonthYearArray, true);
echo "</li>";
} else echo "<li class='month_next smallfontsize'><a class='screenreader'>End of current month</a></li>";
echo "</ul>";
} else {
$latest = $monthlyArchive[count($monthlyArchive) - 1];
echo "<div class='pagination_month msg'><span>View latest posts since "
."<a class='date-narrow' href='".get_month_link($latest->year,$latest->month )
."'>".showMonthYearLocale([$latest->year,$latest->month])."</a>.</span></div>";
}
echo "</div>";
if(1 != $pages)
{
echo "<div class='pagination_bottom'>";
echo "<div class='pagination_prevbtns'>";
if($paged > 2)
echo "<a href='".get_pagenum_link($paged - 2)."'>«</a>";
else echo "<a class='visualonly pagination_disbtn'>«</a>";
if($paged > 1)
echo "<a class='pageprev' href='".get_pagenum_link($paged - 1)."'>‹</a>";
else echo "<a class='pageprev visualonly pagination_disbtn'>‹</a>";
echo "</div>";
echo "<ul class='pagination_slot'>";
for ($i=1; $i <= $pages; $i++)
{
echo "<li>";
echo ($paged == $i)? "<a class='pagination_number current'><span class='screenreader'>Current Page: </span>".$i."</a>":"<a href='".get_pagenum_link($i)."' class='pagination_number' >".$i."</a>";
echo "</li>";
}
echo "</ul>";
echo "<div class='pagination_nextbtns'>";
if ($paged < $pages)
echo "<a class='pagenext' href='".get_pagenum_link($paged + 1)."'>›</a>";
else echo "<a class='pagenext visualonly pagination_disbtn'>›</a>";
if ($paged < $pages-1)
echo "<a href='".get_pagenum_link($paged + 2)."'>»</a>";
else echo "<a class='visualonly pagination_disbtn'>»</a>";
echo "</div></div></div></div>\n";
} else {
echo "<div class='pagination_bottom'>";
echo "<div class='pagination_prevbtns'>";
echo "<a class='visualonly pagination_disbtn'>«</a>";
echo "<a class='pageprev visualonly pagination_disbtn'>‹</a>";
echo "</div>";
echo "<div class='pagination_slot msg'><span class='nopages'>Only 1 page shown.</span></div>";
echo "<div class='pagination_nextbtns'>";
echo "<a class='pagenext visualonly pagination_disbtn'>›</a>";
echo "<a class='visualonly pagination_disbtn'>»</a>";
echo "</div></div></div></div>\n";
}
}
function monthly_archive_array() {
global $wpdb;
$r['type'] = 'monthly';
$where = apply_filters( 'getarchives_where',
"WHERE post_type = 'post' AND post_status = 'publish'", $r );
$last_changed = wp_cache_get( 'last_changed', 'posts' );
if ( ! $last_changed ) {
$last_changed = microtime();
wp_cache_set( 'last_changed', $last_changed, 'posts' );
}
/**
* Filter the SQL JOIN clause for retrieving archives.
*
* @since 2.2.0
*
* @param string $sql_join Portion of SQL query containing JOIN clause.
* @param array $r An array of default arguments.
*/
$join = apply_filters( 'getarchives_join', '', $r );
$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date ASC";
$key = md5( $query );
$key = "wp_get_archives:$key:$last_changed";
if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
$results = $wpdb->get_results( $query );
wp_cache_set( $key, $results, 'posts' );
}
if ( $results ) {
return (array)$results;
}
}
$archiveMonthlyList = monthly_archive_array();
function get_monthly_archive_array() {
global $archiveMonthlyList;
return $archiveMonthlyList;
}
The reason why I decided to remove the range variable is so I want viewers in mobile devices to be able to scroll through pages horizontally (left/right). Of course, for desktop users I could add some JavaScript code that allows me to add/remove numbers based on the current page number and based on the width of the web browser. However, I am a heavy proponent of not using JavaScript whenever possible. I want everyone without JavaScript or for those such as me who use NoScript to enjoy the full potential of my website.
Web development is hard work, but at the end of the day, I enjoyed it a lot. Thanks for reading and enjoy visiting my site!
And note to self: I need to encode HTML code even if it's inside a <pre> tag before I break my website when publishing my post. Don't forget to do the same if you are a web developer as well. Use < for < and > for >. You can also use " for " as well. View the source code for my post to see what I did. In Firefox, open the context menu and choose "View Page Source." Same goes for Google Chrome.
Updated as of July 3, 2021 at 12:44 AM: Added <wbr /> tag to a long function in order to break the function into two lines. This is useful for mobile devices. All today's mobile devices should support HTML5 by now.
Article published: 2021-05-01 08:57
Categories: The World of Computers, Scripting and Programming