Tidying the Media Library With WP Ninjas’ Remove Unused Media Plugin

A few weeks ago, WP Ninjas announced it was stepping into the media optimization plugin market. The team released its Remove Unused Media plugin as a commercial project for tidying storage space. I received a full copy of it and put it through the ropes.

With so many commercial plugins, I am accustomed to the developers creating an entirely new menu item, taking up precious admin real estate. This happens even with those that just have a single screen too. However, I was happy to see the WP Ninjas team tucked everything neatly under “Media” as a sub-menu. We were off to a good start, and things only got better.

When I review plugins, there is one thing that I consistently preach: simplicity. That begins with following the core WordPress UI and sticking as closely to it as the plugin’s features will allow. In essence, don’t make me think about how to use your plugin.

For the most part, Remove Unused Media got the user experience right.

I could nitpick a few design choices with the interface, such as modifying the list table with rounded corners and extra padding. The “filter” sub-navigation also deviates from the standard. And, the “last analysis” message should receive the WordPress admin notice treatment so that it stands out.

These are all core UI elements with unnecessary customizations. However, they did not diminish the experience on the whole. The plugin mostly stuck with the WordPress standard.

The real question is whether the plugin does what it says on the tin. What is the experience of removing unused media like?

It was easy. Users merely need to click the “Start Analysis” button and wait a few seconds. The plugin then has three tabs:

  • Unused Media
  • Used Media
  • Ignored

The Unused Media tab presents an overview of all media that the plugin could not find used on the site. There is a possibility that it missed something. However, I only found one old-school scenario where this happened, which I will dive into later.

Screen that shows media that the plugin detects as unused. Attachments presented in a list table.
Unused media screen.

From this point, end-users can manually delete individual media attachments or use the bulk-delete option. Before doing so, the plugin recommends making a backup of the site — solid advice for any such plugin.

My favorite feature of the plugin was not its primary feature of deleting media. It was actually the “Used Media” screen. Its “Where?” and “How?” columns break down where images, videos, and other files are used and in what context.

Screen from the Remove Unused Media plugin that shows media where and how it is used across the site.
Used media screen.

It reminded me of the “instances” screen for the WordPress admin block directory proposal from 2019. The concept showed where specific blocks were used across the site. Remove Unused Media does the same thing for media files.

The “Ignore” tab for the plugin keeps track of media files that should not be deleted, even if they are unused. Users can click a link from the other screens to add them to the list. This persists after running a new analysis too.

The plugin scans several third-party plugins like Elementor, Beaver Builder, ACF, and Yoast SEO. Some store media instances outside of the post content, such as in custom post meta, and Remove Unused Media searches those specific fields.

Pricing starts at 39€ ($45.38 at today’s exchange rate) for one year of support and updates for a single site. It also has a five-site option at 149€ and a 100-site tier at 299€.

For the first version, the user experience felt solid. However, it does not have much in the way of customizability. That could be a sticking point for users who are looking for a more flexible premium option.

Exploring Alternatives

The plugin is not the first of its kind. The Media Cleaner plugin by Meow Apps is free, routinely updated, and has over 40,000 active installations. It also has a commercial version with more features, such as third-party plugin integration, WP-CLI support, filesystem scan, and live-site analysis.

The issues list from the Media Cleaner plugin in the WordPress admin, showing a list of unused media items.
Media Cleaner plugin results.

The UI for Remove Unused Media feels more like WordPress. Its “Used” tab also shows where (i.e., what posts) and how (e.g., content, featured image) specific media files are used across the site. This feature alone makes it worthwhile for me.

One area where Media Cleaner shines is its option for ignoring (not deleting) attached media. This is a vital feature if users have ever added the old gallery shortcode. At one point, WordPress simply displayed all attached images as a gallery. Eventually, it specified the IDs in the shortcode. However, for those older instances, this was not the case. Without enabling this option, those media items might get queued up for deletion.

The Remove Unused Media plugin does not have such an option. Attached images that are not explicitly used are considered unused. This may not be an issue for most users, but those with old gallery shortcodes should be aware of potential problems.

The baseline features for both are similar. Remove Unused Media gets the edge in its default user interface and experience. However, Media Cleaner has many more options for customizing how the plugin works. Plus, users who cannot afford an upgrade can always run the free version.

This is not to say either is better or worse than the other. Both were solid options in my tests. I just want to merge the best features from each, snagging the interface from Remove Unused Media and the configurability of Media Cleaner.

ARM Assembly Input number and character. Output Number and character

I cannot get the character to input and it does not output.

.equ READERROR, 0 @Used to check for scanf read error. 

.global main @ Have to use main because of C library uses. 

main:
 prompt:


@ Ask the user to enter a number.

   ldr r0, =strInputPrompt @ Put the address of my string into the first parameter
   bl  printf              @ Call the C printf to display input prompt. 

@ Ask the user to enter a character.

   ldr r0, =charInputPrompt
   bl printf

get_input:


@ Set up r0 with the address of input pattern.
@ scanf puts the input value at the address stored in r1. We are going
@ to use the address for our declared variable in the data section - intInput. 
@ After the call to scanf the input is at the address pointed to by r1 which 
@ in this case will be intInput. 

   ldr r0, =numInputPattern @ Setup to read in one number.
   ldr r1, =intInput        @ load r1 with the address of where the
                        @ input value will be stored. 
   bl  scanf                @ scan the keyboard.
   cmp r0, #READERROR       @ Check for a read error.
   beq readerror            @ If there was a read error go handle it. 
   ldr r1, =intInput        @ Have to reload r1 because it gets wiped out. 
   ldr r1, [r1]             @ Read the contents of intInput and store in r1 so that
                        @ it can be printed. 
   ldr r0, =charInputPattern @ Setup to read in one number.
   ldr r1, =charInput        @ load r1 with the address of where the
                        @ input value will be stored. 
   bl  scanf                @ scan the keyboard.
   cmp r0, #READERROR       @ Check for a read error.
   beq readerror            @ If there was a read error go handle it. 
   ldr r1, =charInput        @ Have to reload r1 because it gets wiped out. 
   ldr r1, [r1]             @ Read the contents of intInput and store in r1 so that
                        @ it can be printed. 




@ Print the input out as a number.
@ r1 contains the value input to keyboard. 

   ldr r0, =strOutputNum
   bl  printf


   ldr r0, =strOutputChar
   bl  printf
   b   myexit @ leave the code. 


readerror:

@ Got a read error from the scanf routine. Clear out the input buffer then
@ branch back for the user to enter a value. 
@ Since an invalid entry was made we now have to clear out the input buffer by
@ reading with this format %[^\n] which will read the buffer until the user 
@ presses the CR. 

   ldr r0, =strInputPattern
   ldr r1, =strInputError   @ Put address into r1 for read.
   bl scanf                 @ scan the keyboard.
@  Not going to do anything with the input. This just cleans up the input buffer.  
@  The input buffer should now be clear so get another input.

   b prompt


myexit:

@ End of my code. Force the exit and return control to OS

   mov r7, #0x01 @ SVC call to exit
   svc 0         @ Make the system call. 

.data

@ Declare the strings and data needed

.balign 4
strInputPrompt: .asciz "Input the number: \n"

.balign 4
strOutputNum: .asciz "The number value is: %d \n"

.balign 4
charInputPrompt: .asciz "Input the character: \n"

.balign 4
strOutputChar: .asciz "The character is: %c \n" 

@ Format pattern for scanf call.

    .balign 4
    numInputPattern: .asciz "%d"  @ integer format for read. 

    .balign 4
    strInputPattern: .asciz "%[^\n]" @ Used to clear the input buffer for invalid input. 

    .balign 4
    strInputError: .skip 100*4  @ User to clear the input buffer for invalid input. 

    .balign 4
    intInput: .word 0   @ Location used to store the user input.

    .balign 4
    charInputPattern: .asciz "%c"  @ integer format for read. 

    .balign 4
    charInput: .word 0   @ Location used to store the user input 

@ Let the assembler know these are the C library functions. 

.global printf
@  To use printf:
@     r0 - Contains the starting address of the string to be printed. The string
@          must conform to the C coding standards.
@     r1 - If the string contains an output parameter i.e., %d, %c, etc. register
@          r1 must contain the value to be printed. 
@ When the call returns registers: r0, r1, r2, r3 and r12 are changed. 

.global scanf
@  To use scanf:
@      r0 - Contains the address of the input format string used to read the user
@           input value. In this example it is numInputPattern.  
@      r1 - Must contain the address where the input value is going to be stored.
@           In this example memory location intInput declared in the .data section
@           is being used.  
@ When the call returns registers: r0, r1, r2, r3 and r12 are changed.
@ Important Notes about scanf:
@   If the user entered an input that does NOT conform to the input pattern, 
@   then register r0 will contain a 0. If it is a valid format
@   then r0 will contain a 1. The input buffer will NOT be cleared of the invalid
@   input so that needs to be cleared out before attempting anything else.
@


@ End of code and end of file. Leave a blank line after this.

How to Deploy a Spring Boot App on AWS Fargate

In this blog, you will learn how to deploy a basic Dockerized Spring Boot application to AWS Fargate. AWS Fargate is a serverless AWS environment. Enjoy!

1. Introduction

In a previous post, you learned how to deploy a basic Dockerized Spring Boot application on an AWS ECS Cluster. You learned about the different components like the ECR Docker repository, Task Definitions, the ECS Cluster itself and Services. It is advised to read that post first when these components are new to you. In this post, you will create and deploy the same Dockerized Spring Boot application. This time you deploy it to AWS Fargate. AWS Fargate is identical to AWS ECS Cluster, but this time you will not need to manage the EC2 instances yourself which is a great advantage! It is completely serverless.

Introduction to Helm Charts

A package manager for Kubernetes can take care of the application packaging that is required for deployment on Kubernetes. It is an easy application installation and deployment on Kubernetes. Below are the resources you will need:

Let's say we want to run MySQL on Kubernetes. First, search for MySQL on Artifact Hub, add its rep, and install:

Microsoft Cloud for Financial Services — Architect Perspective

Financial institutions have embraced digital innovation at a recorded pace to adopt new ways of working, serving the financial needs of customers, and keeping the markets performing. Moreover, they have done so while still operating within their control frameworks and regulatory requirements needed to serve in all parts of the world.

According to the 2020 Frost and Sullivan Global Cloud User Survey, “multi-cloud adoption has skyrocketed among financial firms in the past year, up nearly 70%. In addition, hybrid cloud adoption — already higher among financial firms than other industries — is up 8%. In response to the pandemic, financial firms are accelerating their cloud journeys, knitting together disparate IT environments (on‑premises, edge, and multiple clouds) as a foundation for digitalization.”

I have issue adding a sorting function, please guide?

  1. Write a program that would print the information (name, year of joining, salary, address) of employees by creating a class named 'Employee'.
  2. Create a function in the Employee class that finds an employee by the given year of joining.
  3. Create a function for sorting the employees according to their given year of joining.
  4. Create a Display Function for Employee Class.

This is what i was asked you make, i coded everything possible, but was unable to implement this part "Create a function for sorting the employees according to their given year of joining." can someone guide me how to add this? i am having trouble while doing so.

This is what i coded so far

#include <iostream>
#include <string>

using namespace std;

class Employee{
    private:
        string name;
        string address;
        int year;
        int salary;

    public:
        Employee(string, int, int, string);
        string getName();
        int getYear();
        int getSalary();
        string getAddress();
        void displayData();
};
Employee::Employee(string n, int y, int sal, string add)
{
    name = n;
    year = y;
    salary = sal;
    address = add;
}
string Employee::getName()
{
    return name;
}
int Employee::getYear()
{
    return year;
}
int Employee::getSalary()
{
    return salary;
}
string Employee::getAddress()
{
    return address;
}
void Employee::displayData()
{
    cout << getName() << '\t' << getYear() << "\t" << getSalary() << '\t' << getAddress();
}

int main()
{
    Employee e1("Robert", 1994, 500000, "64C - WallsStreet");
    Employee e2("Sam", 2000, 740000, "68D - WallsStreet");
    Employee e3("John", 1999, 600000, "26B - WallsStreet");
    cout << "\nName\tYear\tSalary\tAddress" << '\n';
    e1.displayData();
    cout << '\n';
    e2.displayData();
    cout << '\n';
    e3.displayData();
    cout << '\n';
}

Please do take a look at it and update me accordingly,

Here’s How You Can Purge Big Data From Unstructured Data Lakes

Without a doubt, big data is becoming the biggest data with the passage of time. It’s going above and beyond. Here are some pieces of evidence as to why I said it. 

According to the big data and business analytics report from Statista,  the global cloud data IP traffic will reach approximately 19.5 zettabytes in 2021. Moreover, the big data market will strike a figure of 274.3 billion US dollars with a five-year compound annual growth rate (CAGR) of 13.2% by 2022.  Plus, Forbes predicted that over 150 trillion gigabytes or 150 zettabytes of real-time data will be required by the year 2025. Also, Forbes found that more than 95% of the companies need some assistance for the management of unstructured data, while 40% of the organizations affirmed that they need to deal with big data more habitually. 

After the Lift and Shift: 10 Steps to Optimize Your Cloud Efficiency

The majority of enterprises and companies move into the cloud to leverage performance optimization and efficiently handle their workloads. Although cloud infrastructure proves to be efficient for most companies, there is always some room to further optimize your cloud efficiency by making minor improvement changes to your infrastructure.

If you have just migrated your applications and workload into the cloud, then it’s time to optimize your cloud infrastructure by using our ten most performance-oriented steps below:

The Reports of Perl’s Death Have Been Greatly Exaggerated

Look, I get it. You don't like the Perl programming language or have otherwise disregarded it as "dead." (Or perhaps you haven't, in which case please check out my other blog posts!) It has weird noisy syntax, mixing regular expressions, sigils on variable names, various braces and brackets for data structures, and a menagerie of cryptic special variables. It's old: 34 years in December, with a history of (sometimes amateur) developers that have used and abused that syntax to ship code of questionable quality. Maybe you grudgingly accept its utility but think it should die gracefully, maintained only to run legacy applications.

But you know what? Perl's still going. It's had a steady cadence of yearly releases for the past decade, introducing new features and fencing in bad behavior while maintaining an admirable level of backward compatibility. Yes, there was a too-long adventure developing what started as Perl 6, but that language now has its own identity as Raku and even has facilities for mixing Perl with its native code or vice versa.

Free Resources To Become SRE/DevOps Engineer

The purpose of this post is to centralize a set of free resources in order to present a way to understand and develop Site Reliability Engineering (SRE) and DevOps skills. The content of this post is based on a return of several years of experience in the industry and a willingness to share content that may still be unknown to some people who would like to evolve in their career or open themselves to new opportunities.

The purpose is not to explain what an SRE is or what the DevOps methodology is, but to describe probably the major aspect of these roles: Continuous Learning.

A Haunted House of NoSQL Horrors

Halloween is that frightening time of the year when the veil between the well-ordered world of DevOps and the dark chthonic void of dev/null is thinnest. It's when chaos monkeys reign supreme and Site Reliability Engineers lock the doors and bolt the shutters.

Today we will share with you true life NoSQL horror stories that ScyllaDB's engineers have seen and witnessed in the world of distributed systems. But be forewarned! What you are about to read may just make you shudder deep down to your very hyperthreaded cores.

Blocking an application

Hello. By accepting AVG as my central protection unit I let in AVG browser. I don't want this, because it agressively sets itself as my default browser. I don't want to install it from my system, though, I wan't to disable it from running in my environment. Anybody here who can tell me how to do that? Thank you

Dive Deep Into TiKV Transactions: The Life Story of a TiKV Prewrite Request

TiKV is a distributed key-value storage engine, which is based on the designs of Google Spanner, F1, and HBase. However, TiKV is much simpler to manage because it does not depend on a distributed file system.

As introduced in A Deep Dive into TiKV and How TiKV Reads and Writes, TiKV applies a 2-phase commit (2PC) algorithm inspired by Google Percolator to support distributed transactions. These two phases are Prewrite and Commit.

Code Quality Software That Makes A Difference

"There is no single question to what does the best quality mean? However, one proven approach is comparing how well a given code interacts with its neighbors in the same technical domain."

In the world of software development, code quality often comes to mean a certain level of complexity in a code. The code that is too complex for users or developers to understand or use easily is considered low in quality. Sometimes this means that the code is too complex for even the programmers to understand.

How to Export All Modules to All Modules at Runtime in Java

Due to the new module system, Java 9 does not allow an application by default to see all classes from the JDK, unlike all previous versions of Java. If we try to access some reserved module, we obtain an error like this:
module <module-name> does not "opens <package-name>" to unnamed module.

Everyone knows that we can solve this exception by using the JVM parameters --add-exports or add-opens, but what if we have more environments, and we don't want to have to change JVM arguments across these environments?

Externalizing Your Configurations With Vault for Scalable Deployments

Table of Contents:

  • Introduction
    1. The Solution
  • Setting Up Vault
    1. Creating API Admin Policy
    2. Creating Read-Only user policy
    3. Creating Token attached with API read-only policy
  • 1. Linux Shell Integration
  • 2. Java Integration
  • 3. Python Integration
  • 4. Nodejs Integration
  • 5. Ansible Integration
  • Conclusion

Introduction:

To implement automation for microservices or applications deployed to a large number of systems, it becomes essential to externalize the configurations to a secure, scalable, centralized configuration store. This is necessary to be able to deploy the application in multiple environments with environment-specific parameters without requiring human intervention and without requiring modification to the core application during automated deployments, scaling, and failover recoveries.

Besides the fact that manually managed configurations involve the risk of human error, they are also not scalable for 24x7 large-scale deployments, particularly when we are deploying several instances of microservices across various infrastructure platforms.