Improving Maintenance and Backup Efficiency in WordPress Multisite by Cleaning Orphaned Upload Folders


In large, high-traffic WordPress Multisite environments, system maintenance extends beyond the database and application layer. One area that is sometimes overlooked is the accumulation of orphaned directories within the uploads structure.

When sites are deleted from a WordPress network, their corresponding file directories often remain in the filesystem. Over time, this can create minor overhead in certain scenarios, especially when directories are very numerous or actively scanned by maintenance tools.

Disclaimer: The scripts and procedures below involve bulk filesystem operations. Always have a fresh, verified backup before running them. The author assumes no responsibility for accidental data loss or system damage.

Do Empty Folders Matter?

A common misconception is that empty folders are “harmless” since they occupy zero disk space. It is true that they do not consume meaningful disk space, and their impact on day-to-day system performance is negligible. The actual benefits, however, are realized primarily during maintenance operations that iterate over the entire directory structure:

  • Filesystem cache efficiency: The Linux kernel caches directory metadata (dentries) in RAM. Empty folders don’t pollute the cache meaningfully.
  • Directory scanning latency: In very large directories, creating files or scanning hundreds of thousands of entries may experience minor delays.
    For the vast majority of multisite networks, this effect is rarely noticeable during normal web serving.
  • Maintenance & Backup Efficiency: This is the primary use case. Tools such as rsync, rclone, or cloud backup agents must perform a stat() call on every object during full scans. In directories with tens of thousands of orphaned folders, these scans spend significant time and I/O just traversing “ghost” structures. Cleaning up truly orphaned directories can noticeably reduce backup windows and the load on the storage controller during integrity scans.

Quick, Admin-Friendly Summary

  • Empty folders generally do not affect your site’s day-to-day performance.
  • Only consider cleaning them up if you run full backups, scans, or replication tasks that traverse the entire uploads structure.
  • Focus on truly orphaned directories from deleted sites, not random empty folders, to gain meaningful improvements in operational efficiency.

The Optimization Workflow: A Data-Driven Approach

For multisite installations where cleanup is justified, a systematic approach must ensure safety and efficiency. Here’s a step-by-step method using WP-CLI and Bash:

1. Dynamic Discovery of Empty Folders

  1. Retrieve the latest blog IDs from the WordPress database to define the scan boundaries instead of using static ranges, using wpcli.
    Note: We use wp_blogs as the blogs table name.
  • For each number between 2 and MAX_ID, check if a corresponding directory exists and, if so, determine if it is empty. We use the -print -quit flags with find to ensure the process stops at the first file encountered, making the scan significantly faster.
Bash
# Fetch the maximum blog_id
MAX_ID=$(wp db query "SELECT MAX(blog_id) FROM wp_blogs" --skip-column-names --allow-root)
# Safety check for MAX_ID
if [[ -z "$MAX_ID" || ! "$MAX_ID" =~ ^[0-9]+$ ]]; then
    echo "Error: Could not fetch a valid MAX_ID from database."
    exit 1
fi
echo "Starting filesystem scan up to ID: $MAX_ID..."
for i in $(seq 2 $MAX_ID); do
    dir="YOURFOLDER/$i/"
    # Identify directories that exist but contain no files
    if [ -d "$dir" ] && [ -z "$(find "$dir" -type f -print -quit)" ]; then
        echo "$i" >> empty_folders.txt
    fi
    [[ $((i % 1000)) -eq 0 ]] && echo "Processed up to $i..."
Done

2. Database Cross-Referencing – Empty folder doesn’t mean a deleted blog

An empty folder doesn’t mean a deleted blog. Ensure the folder corresponds to a blog that no longer exists in the database records.

Bash

# Export active blog IDs from the DB
wp db query "SELECT blog_id FROM wp_blogs" --skip-column-names --allow-root > ids_in_db.txt
# Filter for IDs that exist in the filesystem but NOT in the database
grep -F -v -x -f ids_in_db.txt empty_folders.txt > folders_of_deleted_blogs.txt

3. Real-Time Re-Verification (The Safety Net)

Account for race conditions, such as new uploads occurring during the initial scan.

Bash

ROOT_PATH="YOURFOLDER"
cat folders_of_deleted_blogs.txt | xargs -I {} sh -c "find $ROOT_PATH/{} -type f -print -quit | grep -q . && echo {}" > folders_with_files.txt
# Create the final list of confirmed orphaned and empty directories
grep -F -v -x -f folders_with_files.txt folders_of_deleted_blogs.txt > safe_to_delete.txt

4. Controlled Migration (Quarantine) – Move, don’t delete

Move folders to a quarantine directory instead of deleting them immediately to prevent accidental data loss.

Bash

dest="/quarantine/deleted_blog_folders"
mkdir -p "$dest"
while IFS= read -r id || [ -n "$id" ]; do
src="YOURFOLDER/$id"
if [ -d "$src" ]; then
echo "Quarantining: $src"
# Using ionice (idle priority) to protect production I/O
ionice -c3 mv -- "$src" "$dest/"
fi
done < safe_to_delete.txt
# Final Cleanup of temporary metadata files
rm empty_folders.txt ids_in_db.txt folders_of_deleted_blogs.txt folders_with_files.txt safe_to_delete.txt
echo "Maintenance metadata cleared."

Conclusion

  • Empty folders rarely affect system performance in isolation.
  • Cleanup is an operational measure intended to streamline background tasks like backups, replication, and security audits.
  • Following a data-driven, cautious workflow ensures safety while reducing unnecessary filesystem clutter.
  • In large-scale infrastructure, managing orphaned directories is a matter of long-term operational health, rather than a quick fix for site speed.
  • Focus on data-driven cleanup rather than aggressive deletion.

#WordPress #DevOps #SysAdmin #LinuxPerformance #WebInfrastructure #WPCLI #MultisiteOptimization

Translating WordPress with Zero Tech Skills: My Talk at Patras Tech Talks


Last Saturday, November 15, 2025, I had the absolute thrill of speaking at Patras Tech Talk 2025.11 – Going International about how anyone—yes, even with absolutely no tech background—can pitch in to make WordPress fully Greek.

From my own mom, Kyra Chrysoula, scratching her head at “Login” and asking, “What on earth is that, dear?“, to those pesky “Add to Cart” buttons scaring off customers from Greek online shops, we unpacked why translation isn’t just nice to have—it’s a total game-changer.

We dove into the amazing WordPress Polyglots team, the three super straightforward ways to contribute translations to WordPress.org, some hilariously epic (and cringeworthy) translation mishaps, and how you can jump in and start translating in under 5 minutes right here.

  • My full presentation – translated in English is up for grabs right here.

Huge shoutout to the Patras Tech Talks organizers and everyone who showed up with killer questions—the Greek WordPress community is leveling up because of you all!

#WordPressGR #Polyglots #PatrasTechTalks #Translation #WordPress

Παρουσίαση στο Patras Tech Talks: «Μετάφραση WordPress με 0% τεχνικές γνώσεις»


To Σάββατο 15 Νοεμβρίου 2025 είχα την τιμή να παρουσιάσω στο Patras Tech Talk 2025.11 [Going international] το πώς μπορεί ο καθένας, ακόμα και χωρίς ίχνος τεχνικών γνώσεων, να βοηθήσει να γίνει το WordPress 100% ελληνικό και γιατί αυτό είναι σημαντικό.

Από την κυρά Χρυσούλα, την μητέρα μου, που βλέπει το “Login” και απορεί «Τι είναι αυτό παιδί μου;», μέχρι τα κουμπιά “Add to Cart” που διώχνουν πελάτες από ελληνικά e-shop, δείξαμε γιατί η μετάφραση δεν είναι πολυτέλεια – είναι αναγκαιότητα.

Μιλήσαμε για την ομάδα Polyglots του WordPress, τους 3 τρόπους που μπορεί κανείς να μεταφράσει για το WordPress.org, τα επικά (και τραγικά) μεταφραστικά λάθη, και πώς ξεκινάς σε 5 λεπτά στο https://translate.wordpress.org.

H παρουσίαση στα ελληνικά είναι διαθέσιμη εδώ:

Μεγάλο ευχαριστώ στους διοργανωτές του Patras Tech Talks και σε όλους εσάς που ήρθατε και ρωτήσατε – η ελληνική κοινότητα WordPress μεγαλώνει μαζί σας!

#WordPressGR #Polyglots #PatrasTechTalks #Μετάφραση

Φυσικά μετά ως γνήσιοι Έλληνες είχαμε και συνέχεια σε ταβέρνα

Fixing Greek Filenames for og:image Compatibility in WordPress


While working with WordPress and social media, I noticed an issue when sharing images on Facebook. Specifically, images with Greek characters in their filenames wouldn’t show up as og:image thumbnails, even though they were properly uploaded.

To address this, I developed a simple WordPress plugin LS Sanitize Greek Filename, that automatically sanitizes Greek filenames. It converts Greek characters into their Latin equivalents, making the filenames compatible with platforms like Facebook, ensuring that images appear correctly when shared.

This plugin is useful for WordPress users dealing with Greek filenames, helping ensure their images display as thumbnails in social media previews. It’s also multisite compatible!

You can find the plugin on https://wordpress.org/plugins/ls-sanitize-greek-filename/

Informing Subsite Admins about Media Storage space in WordPress Multisite


In WordPress Multisite networks, site administrators (or subsite admins) are often responsible for managing their own site’s content, including media uploads like images and documents. However, there’s a common issue that can go unnoticed: the lack of information regarding their site’s media storage usage. This typically arises from the fact that the storage information displayed only in the Dashboard > At a Glance section is often overlooked, leading to potential space management issues.

The plugin ls-media-storage-info-multisite solves this problem by providing info about the storage usage where is needed most, in Media Library admin page.

The Problem: Overlooked Media Usage Data

In a WordPress Multisite environment, each subsite often has its own collection of uploaded media files. Each subsite admin only sees the info about the storage space usage in their dashboard under At a Glance.

Many admins neglect to check this section, either due to lack of awareness or because the information is not presented in a way that emphasizes the importance of storage management. As a result, subsites might quickly run into storage issues, especially if multiple large files are being uploaded without a clear overview of the available space.

How ls-media-storage-info-multisite Helps

The ls-media-storage-info-multisite plugin tackles this problem by providing info about the storage usage where is needed most by the subsite admins, in Media Library admin page and in the ‘Upload file’ window across all subsites within a WordPress Multisite network.

The Key Benefits for Subsite Admins

  1. Greater Awareness of Storage Space: With more accessible data about how much space their media is consuming, subsite admins are less likely to overlook this crucial aspect of site management.
  2. Proactive Management: Admins can take preventive action, such as cleaning up unused files or asking for additional storage, before hitting critical limits.
  3. Improved User Experience: By maintaining smooth media uploads and avoiding storage overload, subsites ensure that their visitors experience faster load times and fewer issues with media content.

How to Make Use of the Plugin

The plugin is simple to install and set up. Once installed on a Multisite network, it provides an enhanced view of media storage directly from the subsite’s Media Library page.
Admins can use this data to:

  • Regularly check their media storage statistics.
  • Actively manage large media files by deleting unnecessary items or optimizing images.
  • Report storage concerns to the main network admin if space is becoming scarce.

Conclusion

By making storage visibility a priority and addressing the tendency for subsites to overlook the At a Glance storage info, ls-media-storage-info-multisite significantly improves the management of media files in WordPress Multisite networks. It’s a simple yet powerful tool for ensuring that admins are aware of their site’s storage status, ultimately contributing to better performance and easier scalability across the entire network.

If you’re an admin in a WordPress Multisite setup and want to gain better control over your media storage, consider installing ls-media-storage-info-multisite. It’ll help keep your network running smoothly and prevent storage issues before they become a problem.

Related post: How to notify the superadmin when a subsite has low available storage space

Plugin “All Sites Columns for Multisite”


The new plugin available at https://wordpress.org/plugins/all-sites-columns-for-multisite/ is Multisite specific for the superadmin and adds the columns:

  • blog_id
  • public
  • archived
  • mature
  • spam
  • deleted
  • site_id

into the ‘Sites’ admin table in Network administration page, allowing this way the superadmin to sort blogs by the desired column and spot sites which are for example deleted by their owners.

The superadmin can hide the Columns, which are useless for her/him via the ‘Screen Options’ tab.

New plugin released: Easy search and use CC-licensed images for WP


The Creative Commons image search plugin for WordPress we created in Greek School Network is now available as a plugin in WordPress.org with the name “Easy search and use CC-licensed images for WP

The plugin helps you search millions of free photos using the Creative Commons Catalog API then insert the original image into content or set as featured image very quickly.

screenshot-3

The plugin’s features are:

  • Works in WordPress editor and add a button above the content text area and into the “Add Media” pop-up window.
  • Via a pop-up window, allows searching through millions of images using Creative Commons Catalog API power.
  • Allows filtering by a provider
  • Paginated results
  • Quick insert original image or thumbnail with a link to the image URL
  • Use image as a featured image for the blog post
  • WPML compatible
  • Multisite compatible
  • Translation ready (it’s already translated in Greek)
  • Tested up to WordPress 5.2 with Classic Editor plugin

As intended, we already use the plugin in https://blogs.sch.gr, which hosts more than 50.000 blogs. The plugin is available to all its blogs and users since middle May, who has been using it without any issues reported yet.

Read the complete story behind the creation of this plugin at CC Open Source Blog

 

 

Easy search and use of CC-licensed images for WordPress


In CC Open Source Blog you can find a detailed post about the plugin we made for easy search and use of CC-licensed images for WordPress, based on the Creative Commons Catalog API.

https://opensource.creativecommons.org/blog/entries/2019-07-24-cc-search-wp-plugin/

There are still many TODO tasks so, if you want to contribute, you can fork the  plugin at Githubhttps://github.com/lenasterg/wp_ccsearch

 

 

WP CC Search plugin – 0.10


Inspired by the new CC Search tool https://search.creativecommons.org/ I decided to try and make a WordPress plugin based on it. The goal was to have an image search functionality from CC licensed images into the post editor.

Test site

You can test the resulting plugin functionality at http://users.sch.gr/stergatu/wordpress/ by login as testuser, testuser and let me know what you think of it.

Plugin source

You can find the code, contribute and report bugs at  https://github.com/lenasterg/wp_ccsearch

What the plugin does:

WP CCSearch helps you search millions of free photos using the CCsearch API (https://api.creativecommons.engineering/#tag/image) then insert the original image into content or set as featured image very quickly. The plugin is inspired and based on the https://ccsearch.creativecommons.org/ and it wouldnt’t be possible without the Creative Commons Catalog API https://api.creativecommons.engineering/

After the plugin’s activation, you can see the “Image via CCSearch” button above the editor and as option into the “Add Media” pop-up window. By pressing it you can search using Latin characters for an image, browse the returned images, preview an image and its license and adjuct the image settings:

  • use of thumbnail or original image,
  • set the image link (if any).
  • Insert the image into the post or as featured image.

Screenshots:

This slideshow requires JavaScript.

You can try the plugin and let me know what you think of it.

https://github.com/lenasterg/wp_ccsearch

Extend SiteOrigin slider with hide frames functionality


The SiteOrigin Widgets Bundle is one of my favorite plugins, not only because it has a bundle of widgets, but also because it is very extendable and allows other developers to customize and add more features to each widget. Moreover the guys of Siteorigin also provide a guide on how to extend the plugin (see https://siteorigin.com/docs/widgets-bundle/)

Recently I wanted to use the slider of the SiteOrigin Widgets Bundle but I also wanted to be able to  hide a frame or two – not deleted, which is the default option if you don’t want to display them anymore. Hiding and not deleting frames is a useful  feature when you have frames for  special occasions and don’t want to recreate them each time you need them.

The only thing needed is a checkbox “Hide this frame” into the frame’s tab, which then should be “be respected” by the rendering function of the slider, so the specific frame won’t be displayed.

hide_frame
The SiteOrigin slider widget’s settings with the “Hide this frame” functionality added.

So the addition of this extra functionality in the SiteOrigin slider turn out to be very easy.

All you have to do is to add the following code into your theme’s functions.php file


<?php
/**
*
* @param array $form_options
* @param type $widget
* @return array
*/
function ls_extend_sow_slider_form_add_hide_frame($form_options, $widget) {
$form_options['frames']['fields']['hide_frame'] = array('type' => 'checkbox',
'label' => __('Hide this frame', 'so-widgets-bundle'),
'default' => false,);
return $form_options;
}
add_filter('siteorigin_widgets_form_options_sow-slider', 'ls_extend_sow_slider_form_add_hide_frame', 10, 2);
/**
*
* @param type $instance
* @param type $args
* @return array
*/
function ls_slider_hide_the_hidden_frame($instance, $args) {
$frames = empty($instance['frames']) ? array() : $instance['frames'];
if (!empty($frames)) {
foreach ($frames as $i => $frame) {
if ($frame['hide_frame']) {
unset($frames[$i]);
}
}
$frames=array_values($frames);
foreach ($frames as &$frame) {
$link_atts = array();
if (!empty($frame['new_window'])) {
$link_atts['target'] = '_blank';
$link_atts['rel'] = 'noopener noreferrer';
}
$frame['link_attributes'] = $link_atts;
}
}
return array(
'controls' => $instance['controls'],
'frames' => $frames,
);
}
add_filter('siteorigin_widgets_template_variables_sow-slider', 'ls_slider_hide_the_hidden_frame', 10, 2);