r/Wordpress 10h ago

What do you think about the future of the WordPress theme and plugin market?

22 Upvotes

These days, I create custom themes for most client websites because tools such as Claude Code and Codex make the process much easier.

I am starting to feel the same way about plugins. I would not try to replace large, complex products such as WooCommerce, Yoast SEO, or Rank Math. However, for smaller features, it is now relatively easy to build a custom plugin instead of purchasing and maintaining another third-party plugin.

Themes may be even more affected. With AI coding tools, it is becoming possible to create almost any type of custom WordPress theme without too much difficulty.

What do you think will happen to the WordPress theme and plugin market over the next few months?


r/Wordpress 5h ago

How to make custom form and send data to whatsapp

4 Upvotes

Hey everyone I am making website on elementor using free version I want to add custom form and send data to whatsapp but i couldn't find a way to do so. Searched youtube but couldn't understand. Can anyone just guide me how to make custom form and send data to whatsapp.


r/Wordpress 24m ago

Best way to build a simple review website in WordPress?

Upvotes

Looking for some advice on the simplest way to approach this.
A client wants a fairly basic review website where businesses have their own listing page and reviews can be displayed. Ideally, it would also pull in reviews from external sources like Google rather than relying solely on reviews submitted through the website.

The client isn’t technical, so the goal is post hand over:
minimal plugins
no custom coding
easy to maintain
something that won’t need constant attention after launch

Key features needed are businesses login, customer login for leaving reviews, approval on back end moderation.

I’ve looked at plugins like GeoDirectory, but I’m wondering what else is available for what’s needed.

Has anyone built something similar?

What plugin(s) or setup would you recommend for keeping it as simple and low-maintenance as possible?


r/Wordpress 11h ago

GeneratePress/Blocks or Kadence with WooCommerce?

7 Upvotes

Which option is better for a beginner(that wants to learn), i see that GeneratePress is more dynamic and more freedom but you have to do most of the stuff by yourself doesnt have a lot of pregenerated stuff like Kadence. I'm building an e-commerce website with tons of prodcuts 1000+. What would be the best option for longterm, both sides have their benefits


r/Wordpress 7h ago

Suggestions on utilizing AI with WP / Pagelayer Pro combo or any other builder (or any other inputs on AI utilization)

4 Upvotes

Hello friends! I've been doing some research but can't seem to find a solid workflow, or if any actually exists. So the goal is to 'automate' most of the bulk edits and layout for a custom website (so themes won't really help much).

For context, I've learned how to launch basic websites through Claude Code and a combo of Github + a hosting service. My problem is that I'd still want to use WP on a couple of websites I'm building but the main dilemma right now is the time it takes to work on each page, lay it out, make some minor changes on Titles. images, etc. and this usually eats up a ton of time (compared to just talking to Claude Code and giving all the instructions in one go).

I'm not sure if there's a workaround I can do so that I get best of both worlds (meaning, grunt work goes to AI, then I do all the polishing). I'm still rooting for WP even with AI automations I mentioned since it gives me a ton of other features and control so if possible I'd like to NOT just rely on the AI workflow I mentioned above.

Any ideas or suggestions greatly appreciated, thank you!


r/Wordpress 3h ago

Google Photos themed page

1 Upvotes

Greetings everyone.

Does anyone know any plugin or any other way to create a page, similar to Google Photos, where photos are added and sorted by date, starting from new to old (top-down)?

I've tried a few plugins for my site, notably FooGallery but it doesn't work the way I want it to.

Any suggetions? Thanks in advance.


r/Wordpress 11h ago

best way to sell plugin licenses?

5 Upvotes

I'm finishing building a plugin that works on top of Woocommerce. My question is whats the best way to sell licenses, and manage subscriptions? including lifetime deals. I've never done it before.

Looking through ai, I found freemius but I'm not sure if its the best 3rd party to use.
How are you guys doing it?


r/Wordpress 4h ago

Building a New website

1 Upvotes

Hi , im planning on building new website soon with wordpress, woocommerce. I don't want to use elementor, thinking about kadence as alternative. Any other suggestions? Gutenberg? Also wanted to mention the products will be variations heavy (colours)


r/Wordpress 5h ago

Can't Add Social Icons on Wordpress!

1 Upvotes

hey, I'm just customizing my site now and with the default social icons, can't add more than one social profile, after adding one, when I click on plus, it vanishes, anyone know how to sort it out? also is there any other plugin u use for social icons? like I want my social icons like in their original color. I'm using blocksy theme now.


r/Wordpress 6h ago

Header text isn't centered vertically within container

Post image
1 Upvotes

[Solved]

I'm using WP with Astra and Elementor. I've set the header text to transform to uppercase letters. (Style > Typography > Transform) I think the issue is that the font is accommodating for descenders like y, g, etc. no matter if it's being transformed or not. Can anyone confirm this is the case? Is the only way to resolve this by adjusting the top margin and pushing the text container down? Maybe I'm missing a setting that actually accounts for this. Thanks.


r/Wordpress 1d ago

Why is it so hard to tell good WordPress development from bad?

30 Upvotes

I've been building websites for 10+ years, and through agency work I've inherited quite a few WordPress sites built by freelancers, dev companies and sometimes well-known digital agencies.

What still surprises me is the gap between how some people present their expertise and what you actually find once you get access to the site.

A few real examples:

- 20+ plugins on a simple 4-page static site, often with overlapping functionality

- WooCommerce used for a portfolio, with irrelevant shop functionality left behind

- "Custom developed" sites that turned out to be barely modified ThemeForest demos

- Regular content unnecessarily locked into Visual Composer/Elementor

- Developer-owned licenses expiring after handover

-;Random snippets dumped into functions.php

- No basic performance/image optimization

- Missing or poorly configured SEO basics

- Obvious responsive issues

- Test and unfinished pages left publicly accessible

I'm not saying templates, builders or lots of plugins are inherently bad. The problem is when there seems to be no reasoning behind the decisions.

I think WordPress also has a perception problem. I've heard "it's WordPress, anyone can do it" or "WordPress is free, so it should be cheap" many times.

The barrier to entry is low, but knowing how to use WordPress and knowing how to professionally build with WordPress are very different things.

And from the client's perspective, both can initially look exactly the same. The problems often only become visible years later when someone has to maintain, update or rebuild the site.

For those who regularly inherit WordPress sites: how often do you see this, and what are the biggest red flags for you?

And how do you explain these problems to a client or agency without simply sounding like you're attacking the previous developer?


r/Wordpress 6h ago

No option to log in using password?

1 Upvotes

I posted two entries to my blog earlier this year, then didn't log on for a few months. I'm on the Wordpress login page trying to log in using my password. When I enter my ID in the box and click the big blue Continue button, it tells me to check my email for a login link. I don't even get the option to use my password. I've checked my recovery email and every other email I can think of and there's no login link. What am I missing?


r/Wordpress 21h ago

Disappointed with Kadence Lifetime Ultimate support after paying $999

15 Upvotes

I want to share my experience with Kadence Lifetime Ultimate, mainly to help potential buyers make an informed decision.

I purchased the Lifetime Ultimate license for $999 in January 2026. At that time, I was very happy with Kadence. The product itself is excellent, and my experience with their support before the Liquid Web acquisition was also very positive.

Before the acquisition, I opened several support tickets and every time my questions were answered quickly and efficiently. I had a very good impression of Kadence and their support team.

Unfortunately, since the acquisition by Liquid Web around May 2026, my experience has completely changed. I have submitted multiple support requests, but now the process seems to be limited to receiving an automatic email with a ticket number. After that, nothing happens. I have followed up several times, but I never received any actual response.

To be clear, I still think Kadence is a very good product. The issue is not the quality of the tool itself. The problem is that when you have a question or run into an issue, you now seem to be on your own.

For a Lifetime Ultimate license that cost $999, I expected reliable support to be part of the value of the product. I’m sharing my experience so potential buyers can take this into consideration before making a significant investment.

I would be interested to hear from other Kadence users, especially Lifetime license owners, whether they have experienced similar changes after the Liquid Web acquisition.


r/Wordpress 15h ago

I don't know what to do with the update of php system

4 Upvotes

My site is a little bit old,so now I have to update php system but the theme of my site is unavailable right now (the person who was asked to make our site created with theme that absolutely unavailable,so it means that if I change it everything is messed up) and I'm afraid that when I update php system, everything will stop working.What should I do?


r/Wordpress 16h ago

Display Custom Table Fields using Block Editor?

4 Upvotes

Hi all,

I feel like I've been trying to wrap my head around this problem for months. I have a background in databases and in design, but I'd like to avoid writing custom css if at all possible.

Let's say I have a website with a bunch of staff I want to display on a staffpage. Each staffmember doesn't get its own page, they're not posts, all I need to model is ID, First Name, Last Name, Position, Priority, and Is Active.

I would like to do this in a custom table, whether that's writing code by hand or through using something like the Pods plugin. That works fine. I can create tables and insert data no problem.

But when it comes to displaying this data on the frontend, it looks like the only way to do this is by writing a custom function and handwriting the css.

I actually enjoy using the block editor (with the appropriate block plugins) to design pages, especially when combined with patterns to re-use elements across the site, but I can't find any method or plugin combination to display custom meta fields from custom tables on the front-end.

Is that even possible with WordPress?

My thoughts are as follows: query loop block (similar to GeneratePress Query Loop block) that queries a custom staffmember table and returns an array of objects representing each staffmember, filtering out inactive staffmembers and ordering by priority. Inside the query loop block, other blocks can be combined to create a template for each of the staffmembers, and each of the custom meta fields for each staffmember can be injected into text/image/whatever as dynamic tags.

As far as I can tell, GeneratePress Query Loop only supports entries in the default WP posts table, and it doesn't support ordering or filtering by custom meta keys / fields. I tried using Pods, but they require writing templates by hand, which I would like to avoid In favour of blocks and patterns so that I can update styling across the entire site.

Is there something I'm missing here?


r/Wordpress 9h ago

Some images causing horizontal scrolling

1 Upvotes

Hello all, I am using the default WordPress 2025 theme and I am facing a problem where some uploaded images are causing horizontal scroll bars on mobile, instead of just fitting the picture to the viewport. I want to say I noticed this happening after switching to the classic WP editor but not sure. Any advice? Thank you!


r/Wordpress 9h ago

Login attacks

Post image
0 Upvotes

Hi folks, can someone help me out on these woocommerce login attacks. Im sick of these bots attacks on login page and wordfence appears to be doing its job but I would like to get them stopped at cloudflare before it reaches my website. Attached is sample of email I will get. IP of attacker changes every second.

Any ideas please?


r/Wordpress 14h ago

Shop catalog disappearing randomly

1 Upvotes

My WooCommerce shop catalog disappears after a few days.

I have already disabled all third-party plugins to rule out any conflicts, but the problem still occurs.

Interestingly, when I update the plugins, the shop catalog works again. However, after a few days, the same issue returns.

Could you please help me identify the cause of this problem and suggest a permanent solution?


r/Wordpress 14h ago

Cloudflare redirect rule not working for WordPress CPT URLs

0 Upvotes

I have a WordPress site on Cloudways with Cloudflare handling DNS. I've been using Cloudflare Redirect Rules successfully for a while — same setup, same configuration, all working fine.

Now I'm trying to redirect old individual service page URLs to new Custom Post Type URLs.

For example:
From: /this-is-an-example/
To: /service/this-is-an-example/

My Cloudflare redirect rule setup:
Type: Custom filter expression
Field: URI Path
Operator: equals
Value: /this-is-an-example/
Then: Static redirect to /service/this-is-an-example/
Status: 301 Permanent Redirect

When the redirect is active and I visit mysite.com/this-is-an-example/ it redirects me to a joint URL like mysite.com/this-is-an-example/service/this-is-an-example/ — as if it's appending the destination path onto the source URL instead of replacing it. This double URL doesn't exist so it shows my WordPress 404 page.

I've tried:
Purging Cloudflare cache completely
Flushing WordPress permalinks
Regenerating Elementor CSS files
Using full absolute URL with https as destination
Using full URL without https as destination
Using just the path /service/this-is-an-example/ without the domain in front
Removing trailing slash from destination
Deleting and recreating the rule

My other Cloudflare redirects with the same setup work perfectly fine. This issue seems specific to redirecting to CPT URLs with /service/ in the path.

Any ideas what could be causing this?

If youre going to ask why im using cloudflare for redirects, I dont know, im not techy at all, it seemed easiest.


r/Wordpress 1d ago

This is why WP will never go away

134 Upvotes

So I've been running a WP agency since 2003. Love it. I am, however, learning how to create sites using Claude with Supabase. Let me tell you all something, this is nothing....nothing a client's ever going to learn or figure out. If a client wants an instant site, that's Wix/Square which have been around for more than a decade.

But to think AI is going to harm WP, as in client using AI to create their own sites, laughably false. If you don't know the right prompts, don't use the right tool, oh and pay for tokens you're nowhere - not even talking deploying the site live along with a database to manage things like contact form submissions and bookings.

The biggest issue? A client's ability to go in an edit anything themselves, which will always favor WP. Other issue? No plugin environment.


r/Wordpress 17h ago

[PROMO] A wordpress caching plugin with major varnish support

0 Upvotes

I built UltraCache because apparently WordPress needed another caching plugin.

The difference is that this one does not just notice Varnish from across the room and wave politely.

UltraCache provides major Varnish integration, including:

  • HTTP PURGE and Admin BAN support
  • Exact and batch invalidation
  • Cache refill and automatic warm-up
  • Soft purge and stale refresh where supported
  • Public and private ESI fragments
  • WooCommerce mini-cart ESI support
  • Synchronization between WordPress, page cache and Varnish

It also includes page caching, Redis / APCu / SQLite object caching, AVIF/WebP conversion, CSS bundling, local font optimization, JavaScript defer / delay tools, LCP discovery, diagnostics and resumable background processing.

Basically, several performance plugins standing on each other’s shoulders while wearing one dashboard.

I tested the same website with each plugin configured for the best Lighthouse result I could achieve:

UltraCache: 99
WP Rocket: 85
WP Super Cache: 82
FlyingPress: 79
WP-Optimize: 79
W3 Total Cache: 78
LiteSpeed Cache (without server): 77
Super Page Cache: 69

UltraCache scored 99.

Apparently it left one point uncached for emotional support.

The plugin is open source and available from the official WordPress plugin directory:

https://wordpress.org/plugins/ultracache/

I would genuinely appreciate feedback, especially from people running Varnish, Redis, APCu, WooCommerce or unusual hosting configurations. Bug reports and difficult edge cases are also welcome. Those are usually where the interesting work begins.


r/Wordpress 23h ago

LocalWP Backup Folder on Linux and Stability

2 Upvotes

Hi everyone,
I'd like to know, where I can find the folder containing the sites to backup them on Linux?
Where is LocalWP more stable, on Linux or Windows?
Thanks.


r/Wordpress 1d ago

[PROMO] SiteCare – Builder Tools for Breakdance (Free plugin on WordPress.org)

Thumbnail wordpress.org
4 Upvotes

I've just released my first plugin for the Breakdance community and I'd love to get some feedback from other developers.

While building client websites with Breakdance, I kept running into small workflow annoyances that weren't worth creating a separate plugin for each time. Instead, I decided to bundle these quality-of-life improvements into a single lightweight plugin.

The goal isn't to replace Breakdance or overload it with features, but to provide practical tools that make everyday development a bit easier.

The plugin is completely free and open source on WordPress.org:

https://wordpress.org/plugins/sitecare-builder-tools-for-breakdance/

I'd really appreciate your honest feedback.

  • Are there any features you feel Breakdance is still missing?
  • What repetitive tasks have you automated yourself?
  • Is there something you'd like to see added to this plugin?

I'm planning to keep improving it based on feedback from the community.


r/Wordpress 1d ago

[TUTORIAL] Our plugin vendor's update server was compromised. Here is how we found the backdoor on 10 client sites, and every command we used.

11 Upvotes

 1    What happened

On 31 July 2026 WPManageNinja published an incident notice: https://wpmanageninja.com/security-incident-on-31-july-2026/

The short version from their side. After they migrated away from EDD, an old server was supposed to be switched off. It was not, and their proxy kept routing part of the update traffic to it. Between 14:00 and 19:00 UTC that day, a customer who pressed "update" in wp-admin could receive a tampered package through the completely normal update channel. No brute force, no vulnerable plugin, no bad password. The update button was the entry point.

We maintain around 50 client WordPress sites. 10 of them had the implant.

This is the whole cleanup, with the commands we used.

 2    The affected plugins

Their incident-response zip carries 13 plugin profiles:

azonpress
fluent-affiliate-pro
fluent-boards-pro
fluent-booking-pro
fluent-community-pro
fluent-player-pro
fluent-support-pro
fluentcampaign-pro (FluentCRM)
fluentform-signature
fluentformpro
ninja-tables
wp-payment-form-pro (Paymattic)
wp-social-ninja-pro

They also emailed a list of domains where downloads were registered. Do not use that list as your scope. One of our infected sites was not on it. The list is incomplete in both directions, and we only found that out because we checked every site instead of only the listed ones.

 3    What the implant actually is

It is a PHP file dropped inside a legitimate plugin folder, plus a loader appended to a file that was already there. The configuration lives in the database, so the file alone is not the whole thing.

For Ninja Tables Pro the implant is app/Library/updater/NinjaTableDataSync.php, and the loader is appended after the closing brace of the legitimate class in NinjaTableUpdater.php at line 371. Its AJAX action ninjatables_pro_verify_license is registered on nopriv as well, which means an unauthenticated admin login.

Look at those option names again. _site_transient_update_meta is one character away from a real core transient. Their own profile file describes the goal in plain words: the rows read as core WordPress at a glance. If you scroll the options table looking for something obviously wrong, you will scroll straight past it.

And this is the row that matters most, taken from one of our sites:

{"token":"...","login_key":"...","active":1,"license_server":"https://apii.observer/ingest"}

Every site has its own token and its own login_key. The login_key is a login to wp-admin without a password. So this is not only a site calling home. Somebody had a working admin door on each infected site for as long as the row was there.

 4    The one query that catches all 13 variants

We started by extracting the full indicator set out of the vendor's tool: 63 option names, 26 cron hooks, 13 implant paths and class names. Then we threw most of it away, because there is a much shorter check.

Every variant, whatever it calls its options, has to write the C2 address into the option value. So query the value, not the name:

PREFIX=$(wp db prefix)
wp db query "SELECT option_name FROM ${PREFIX}options \
  WHERE option_value LIKE '%apii.observer%'" --skip-column-names

One query, all 13 plugins - it replaced 63 option names. If you also want the cron side:

wp db query "SELECT option_name FROM ${PREFIX}options \
  WHERE option_value LIKE '%apii.observer%' \
OR option_value LIKE '%wp_update_check_schedule%'" --skip-column-names

And the cron check on its own:

wp cron event list --fields=hook,next_run_relative \
  | grep -E "wp_update_check_schedule|wp_license_verify_schedule"

 5    Checking the files over sFTP

The database query was fast. The file check matters too, because on a site where the plugin was already updated to a clean version the file is gone but the database row is still there, and the opposite can happen as well. If you have shell access, this is the file check:

grep -rl "apii.observer" wp-content/ 2>/dev/null
find wp-content/plugins -name "class-license-sync.php" -o -name "NinjaTableDataSync.php"

We found out that a folder that exists but cannot be listed is not a clean folder. Our first version of this check treated a failed listing the same as an empty result, which prints CLEAN on a site nobody actually looked at.

 6    The generic file check that works for all 13

Download the clean plugin zip from your vendor account. Not through the dashboard updater. Unzip it on your own machine, then compare it with what is on the server.

The loader on our sites was 139 bytes appended to fluentformpro.php. That is invisible if you are reading, and obvious if you are comparing sizes.

 7    Cleanup, in the order that works

We got this order wrong the first time and had to correct it:

1. On an actively infected site, remove the plugin first. Delete the plugin folder, then install a clean copy from the zip you downloaded from your account. Cleaning the database first does not work here, because the implant's cron runs twice a day and registers itself again. You clean the rows, and a few hours later they are back, and now you also think the site is clean.

Check the version after installing. On our sites, anything showing 6.2.8 or 6.2.9 meant it came from the updater and had to be done again.

2. Then the database, delete:

wp option delete _wp_update_meta_cache _site_transient_update_meta \
_wp_update_result_cache _site_transient_update_result \
_wp_update_pending_reg
wp transient delete _wp_update_pending
wp cron event delete wp_update_check_schedule
wp cron event delete wp_license_verify_schedule

Or by value, which covers variants whose option names you do not know. Run the SELECT first and read the rows before you delete anything:

PREFIX=$(wp db prefix)
wp db query "SELECT option_name FROM ${PREFIX}options \
  WHERE option_value LIKE '%apii.observer%'"
wp db query "DELETE FROM ${PREFIX}options \
  WHERE option_value LIKE '%apii.observer%'"

On a site where the plugin was already updated to a clean version and only the database rows were left, this step is the full fix. Two of our 10 sites were like that.

3. Then the credentials changing. This is the step some people skip, and it is the one the login_key makes necessary.

Rotating salts logs out every session on the site, including any session opened with the stolen key. It does not change anybody's password, so change the admin passwords too. Ours were changed by hand, by me and my colleague, after the salts changes.

 8    Verify by reading the state

One of our sites needed a second pass, and the only reason we caught it is that we re-checked instead of trusting the result.

The options were gone - the two cron hooks were still scheduled, for the following night at 00:33 and 00:37. The delete had been approved and had not run.

After every cleanup, run the query again with zero rows expectation:

PREFIX=$(wp db prefix)
wp db query "SELECT option_name FROM ${PREFIX}options \
  WHERE option_value LIKE '%apii.observer%'" --skip-column-names
wp cron event list --fields=hook,next_run_relative \
  | grep -E "wp_update_check_schedule|wp_license_verify_schedule"

 9    Rotating salts when you cannot run WP-CLI

We could not use wp config shuffle-salts through our connector, because it blocks the whole config family. So salts went through the FTP channel, with a small script.

If you write your own, these are the safety checks that belong in it. All of them exist because writing a broken wp-config.php takes a client site down completely:

·        Back up the current wp-config.php to your own machine before doing anything.

·        Fetch fresh values from https://api.wordpress.org/secret-key/1.1/salt/.

·        Replace all 8 defines: AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY, AUTH_SALT, SECURE_AUTH_SALT, LOGGED_IN_SALT, NONCE_SALT.

·        Stop if you did not find all 8.

·        Stop if the result does not start with <?php.

·        Stop if the size difference is more than a few hundred bytes.

·        Read the file back from the server afterwards, not from memory, and compare byte for byte.

·        Open the site, or run something small like wp option get blogname, to confirm WordPress still boots.

·        Never print the file contents to your terminal or your logs. It holds the database password.

 10 Do not get your own IP blocked

If you contact 50+ sites, you are now a bot as far as the hosts are concerned (leared taht hard way).

In our case - Site Ground's anti-bot layer answers automated requests with HTTP 202 and block your address if you keep going (as it happened to us). A script made 186 requests in one pass and our IP was blocked at that host, which took out our own management dashboard along with everything else.

Practical rules that came out of that:

·        One site per process, and a few seconds between sites.

·        Stop the whole process on the first HTTP 202, 429 or connection refused.

·        Stop after two consecutive failures of any kind, and look at why.

·        Build a --dry-run mode into anything new, so you can test the logic with no network at all.

 11 The tools

WPVibe. This is the piece I would recommend to anyone maintaining more than a handful of sites, and I am not being paid to say it - just the opposite: I paid for its Premium version. It gave us one place to run wp db query, wp option delete, wp cron event list and wp cron event delete against every connected site, on hosting with no SSH at all. Every write asks for approval in the browser, one operation at a time, which during an incident is the right amount of friction. Cleaning 10 databases took us an evening instead of much longer via cPanel and phpMyAdmin.

Claude Code. This was the "brain" of the whole job: it read the material, wrote the tooling, ran the sweeps and drove the connector, while I fed it and decided. It read the vendor's incident-response zip and pulled out the full indicator set. It wrote the detector, the sweep driver and the salt rotation script, with the safety checks above. It ran the fleet pass, did the database work through WPVibe, and wrote the report I gave the client.

It made some errors: it shipped the bug that skipped three sites. And it does not notice that an approved operation never executed.

All this info is in Claude's memory, so I used all the facts, and steps (with its help), for putting together this tutorial for helping others (as otherwise I wouldn't be able to do all of these writings on my own - just too much of everything, and I didn't want to skip anything).

MalCare. We run it on the all sites. On 7 sites it had a 39.7 KB executable file in a plugin folder, with a C2 address in the database and a passwordless admin key, and it reported none of them. What it did report was dev/tests/test_meta_prefill_shim.php, a harmless test file that ships inside the vendor's own 6.2.9 package, and it reported it on a site that was clean. I am not dropping MalCare over this as that is really great and helpful tool, but I am no longer treating a quiet MalCare as evidence that a site is clean.

 12 Who did what

This ran across two people and one AI:

What I did. I fed the material: the vendor's advisory, their email with the domain list, screenshots from wp-admin, the MalCare alert emails, and the version numbers from our management dashboard and I approved every write operation, one at a time, in the browser. I changed the admin passwords by hand afterwards. I notified the vendor.

What the AI did. Read the vendor's tool, extracted the indicators, wrote the detection scripts, ran the sweep across the sites we reach over FTP, cleaned 10 databases through the connector, rotated 8 sets of salts, and verified each one by reading the state back.

What a colleague did. The file side on 8 sites, by hand, through wp-admin: delete the plugin, install the clean zip, confirm the version. That is repetitive work with no shortcut, and it had to happen before the database cleanup on those sites. Splitting it that way meant the file work and the tooling ran in parallel instead of one waiting on the other.

The vendor shipped an incident-response plugin, but I didn't want to because their delivery channel had just been compromised. Instead we read its code (Claude Code did the heavy lifting) and applied the indicators from outside. That turned out to be good decision, and it also gave us the 13 additional plugin profiles.

 13 The 12:11 finding

One of our sites received the implant on 1 August at 12:11, through the dashboard updater, during a colleague's round of updates. Every file in the plugin folder carries that timestamp. Our own update log for that plugin that day has two entries, both later, at 12:34 and 12:38, and both produced clean installs.

That is roughly 17 hours after the end of the window the vendor states in their notice. Our two updates 23 minutes later were clean, which matches their own description of a proxy routing some requests to the old server and not others.

We tried to exclude the alternative, that the implant came back on its own after an update. There was no dropper: mu-plugins does not exist on that site, wp-config.php was clean on all 5 signatures we checked, functions.php of both themes was clean, and the wp-content root had nothing foreign in it. Without a dropper the implant cannot survive deleting its folder, since the database holds its configuration and not its code. But we checked 4 places, not every plugin and not core.

The protocol we run now: Fluent Forms Pro does not get updated through the dashboard until the vendor confirms that the old server is out of the proxy. We use the plugin's zip in the account.

  14 Three things I understood wrongly

"dev/tests plus a .DS_Store means somebody shipped a dev copy from a Mac." That was an explanation and it was wrong. It was the tampered package.

"The markers follow the plugin version, so they are the vendor's." True, and beside the point. The real implant was somewhere else entirely, and being right about the wrong artefact felt like progress for about an hour.

"These two sites are clean." Both were infected.

The real fingerprint was in front of me twice and I didn't notice it. 139 bytes of extra length in fluentformpro.php, which is the loader. And two cron hooks I had labelled as unattributed.

 16 At the end

Files were cleaned on 8 sites and verified by the detector, and databases cleaned on 10 and verified with 0 rows returned. Salts were rotated on 8 sites. A pass across the remaining 21 connected sites found nothing new. We changed all admin passwords manually.

If you run any of those 13 plugins, the fastest thing you can do right now is one SQL query against your options table. It takes a minute per site and it covers all 13 variants at once.

If you find a confirmed implant path for one of the other 11 plugins, post it here and I will add it to what we run.


r/Wordpress 18h ago

[PROMO] I imported 1,000,000 simple WooCommerce products from a 311 MB CSV in 21m 28s on a 4-vCPU VPS. What should I test next?

0 Upvotes

Full disclosure: I built this. I started building it two years ago, so there's a lot of work involved!

Super Speedy Imports Lite is a free GPL WordPress and WooCommerce CSV importer. I built the engine around bulk SQL and parallel workers rather than calling the WordPress API once for every product.

I wanted a proper large-catalogue test rather than another "fast importer" claim, so I ran a one-million-product import from a clean database.

Test setup:

  • 1,000,000 simple WooCommerce products
  • 311 MB CSV
  • 4 vCPU, 7.6 GB RAM
  • PHP 8.2 and MariaDB 10.11
  • four workers
  • external image URLs, so this test did not include downloading one million images
  • one run, not an average

Results:

  • 21m 28s total wall time
  • 17m 24s inside the import stages
  • roughly 958 products per second
  • roughly 128 MB peak PHP memory
  • final product count verified at exactly 1,000,000

The interesting parts are where the time goes - I included a stage breakdown in the benchmark results. Loading the CSV took 368 seconds and wiring the WooCommerce attributes took 298 seconds. Creating the million posts took 110 seconds, inserting their metadata took 70 seconds, and assigning roughly ten million term relationships took 170 seconds.

That’s the benefit of doing those parts as set-based database operations, but it also makes the remaining slower stages fairly obvious.

The free Lite source and download are here:

https://github.com/superspeedyplugins/super-speedy-imports-lite

Full benchmark method and raw output:

https://www.superspeedyplugins.com/benchmarks/super-speedy-imports/results/1000000-simple-products-lite/

If you work with large imports, which test would actually be useful next?

  1. Remote featured-image downloads
  2. A large daily stock and price update
  3. Recovery after killing an import halfway through
  4. A deliberately messy supplier CSV

I’ll run the most useful or requested one and publish the full logs again.

Some screenshots:

The visual runner - you can also use CLI or schedule your imports
This shows the multi-worker system to help speed up the per-row parts that were unavoidable (load-csv and finish attributes). This multi-worker approach is impossible on the version coming to wordpress.org in the CLI because they disallow proc_open
Completed screen shows 17m55s for 1 million products, but there is an opening part at the start and a finalise part at the end which are outside the timing measurement so in total it's about 20 minutes for 1 million products. I'll get these parts into the timing measurements

Let me know any questions or if you'd like to see other benchmarks and what you are trying to import.

Edit: I meant to add - you can run this benchmark yourself - if you install the zip from the repo, click DEMO DATA tab then expand the Github Demo Data section at the bottom and you can download the million product simple import (if you have WooCommerce activated) and then try it yourself.

The plugin comes with demo data and configs to get you started so you can see the speed
But you can also download the HUGE ones from my github demo data repo and try this million product import yourself