# Database Security Checks — What Each Finding Means

> GuardPress Database Security runs 15 sub-checks daily across users, configuration, malware patterns, cleanup, and server version. What each finding means.

- Canonical: <https://royalplugins.com/support/guardpress/database-security-checks-explained/>
- HTML version: <https://royalplugins.com/support/guardpress/database-security-checks-explained/>

---

GuardPress Database Security runs **15 sub-checks** across users, configuration, cleanup, malware patterns, and server version. Findings come back at four severity levels, and the right action depends on which sub-check fired. This is the reference for what each finding actually means, the action to take, and when a finding is safe to ignore. If you’re staring at a Critical finding for “Suspicious Post Content” or trying to decide whether 1,200 expired transients are a real problem, start here.

### Where to find the scan

**WP Admin → GuardPress → Database**. The page shows the last scan time, severity counts (Critical / High / Medium / Low / Auto-Fixable), and the full list of findings. Use **Run Scan Now** to re-scan on demand, or wait for the next daily scheduled scan.

## When the Scan Runs and Where Findings Show Up

Two ways the scan kicks off:

- **Daily** — via WordPress’s built-in cron, on the `guardpress_daily_scan` hook. The exact time depends on when WP’s cron tick first fires on your site after the previous day’s scan; in practice it runs roughly every 24 hours.
- **On demand** — click **Run Scan Now** on the Database Security admin page. The on-demand AJAX handler is registered regardless of whether the daily scan is enabled in settings, so the button always works.

Findings are stored in the `guardpress_database_results` WordPress option and surface in three places:

- **The Database Security admin page** itself — full list of findings, severity counts, and (for sub-checks that support it) one-click cleanup buttons.
- **The audit log** (**GuardPress → Audit Log**) — one entry per scan, action `database_scan_completed`, summarising how many issues were found and how many were critical/high.
- **Security alert emails** — the scan dispatches a notification via `GuardPress_Notifications::send_security_alert()` when at least one finding is Critical or High severity. Low / Medium findings don’t trigger an email on their own.

## Severity Ladder

Every finding is tagged with one of four severities. The cutoff for “you should be emailed about this” is Critical or High; Medium and Low are awareness-level.

- Critical — act today. Almost always a malware indicator (suspicious post content, tampered `active_plugins`, poisoned capabilities, rogue cron events).
- High — act this week. Strong security signal (default `admin` username, brand-new admin accounts, MySQL EOL, admin users with inconsistent capability metadata).
- Medium — act this month. Hardening recommendation or performance gap (default `wp_` table prefix, too many admin accounts, autoloaded options creeping into the 1–3MB range).
- Low — informational. Database hygiene (orphaned meta, expired transients, post revisions, spam/trash, zombie cron events).

Severities are heuristics, not a CVE rating

A Low “Orphaned Post Meta” finding is genuinely low for most sites. But a Critical “Suspicious Post Content” finding on a multi-author WP site that publishes code tutorials may be a false positive (legitimate code blocks containing `base64_decode` for instruction). Use severities as a triage order, not the final word.

## The 15 Sub-Checks

Each scan runs every sub-check below in order. Sub-checks emit zero or more findings depending on what they detect. The list is canonical against GuardPress 1.6.37; sub-checks 12–15 (malware / tampering family) were introduced in 1.6.10.

#### Medium Default Table Prefix

Your WordPress tables use the default `wp_` prefix.

##### Check

Reads `$wpdb->prefix` and compares it to the literal string `wp_`. Fires only when the prefix is exactly the default.

##### Why it matters

Mass-targeted SQL injection attacks and automated scanners assume table names like `wp_users` and `wp_options`. A non-default prefix breaks the assumption and turns precision attacks into trial-and-error.

##### Fix

Change the prefix at the install level (best done at WP install time). Mid-life prefix changes require renaming every table, updating `wp-config.php`’s `$table_prefix`, and updating two columns inside `wp_options` + `wp_usermeta` that reference the prefix in row data. Several plugins automate this safely — do a full backup first via [SiteVault Pro](https://royalplugins.com/sitevault/).

##### Safe to ignore

When you weigh prefix change risk against the marginal protection gain, many small sites legitimately decide to skip this and rely on the firewall + brute-force layers instead. The finding is Medium, not High, for exactly this reason.

#### Medium Too Many Administrators

More than 5 user accounts hold the `administrator` role.

##### Check

SQL count of users whose `wp_capabilities` usermeta row contains the string `administrator`. Fires when the count exceeds 5.

##### Why it matters

Every admin account is a credential pair that, if compromised, gives an attacker total control. A practical security ceiling is one admin per actual human who needs full plugin/theme/user-management control; everyone else gets Editor, Author, or Shop Manager. Six or more admins almost always means stale staff accounts or contractors that never got demoted.

##### Fix

Go to **WP Admin → Users → Administrators**. Audit the list. Demote anyone who doesn’t need full admin to Editor or Shop Manager; delete anyone who shouldn’t have access at all.

##### Safe to ignore

If your team genuinely needs that many admins (small agency managing a client’s site with multiple stakeholders), you can leave it — the finding will keep appearing on every scan but doesn’t emit an alert email (it’s Medium, not High).

#### High Default Admin Username

A user account with the username `admin` exists.

##### Check

`get_user_by('login', 'admin')`. Fires if any user has that exact login.

##### Why it matters

`admin` is the first username brute-force scripts try, every time. It cuts an attacker’s required guess space in half: they now only need the password. If the account also has a weak password, this is a one-step compromise.

##### Fix

1. Create a new admin user with a non-default username (your name, a randomised handle, anything but `admin` / `administrator` / `root` / `wp_admin`)
2. Log in as the new user
3. Delete the old `admin` user from **Users**, attributing their content to your new account

##### Safe to ignore

Almost never. The only edge case is a deeply locked-down install where the `admin` account has been moved off-network entirely and cannot log in via wp-login.php at all (deny rules in nginx/Apache). Even then, fixing it is faster than explaining it.

#### High Suspicious User Registrations

More than 10 new user accounts registered in the last 24 hours.

##### Check

SQL count of users with `user_registered > NOW() - 24 hours`. Fires when more than 10 new users appeared in the last day.

##### Why it matters

On a site that doesn’t actively run registration campaigns, ten new accounts in a day is a spam bot signal. Bots often register accounts to post comments / spam profile fields / drop SEO backlinks. On a WooCommerce store running a paid ad campaign, ten organic registrations a day is normal — context matters.

##### Fix

Go to **WP Admin → Users → All Users**, sort by newest, review the recent additions. Bulk-delete anything obviously bot-shaped (random gibberish usernames, throwaway email domains, no profile data). Then add a captcha to your registration form (Royal Comply or the GuardPress Turnstile integration, depending on your setup).

##### Safe to ignore

If you run a busy community/shop/membership and 10+ daily registrations is your normal cadence, this finding will fire constantly. You can leave it; the Critical/High classification doesn’t escalate to anything that bricks the site, just an email.

#### Low Users Without Email

One or more user accounts have no email address.

##### Check

SQL count of users with `user_email = ''` or `user_email IS NULL`.

##### Why it matters

WordPress’s standard registration flow always sets an email. Empty-email accounts came from somewhere else — a database import that lost the column, direct SQL inserts, or (rarely) an injected account from a poorly-formed exploit. Often benign; occasionally a tell.

##### Fix

Open the user in **Users → All Users** and either set a valid email or delete the account if it shouldn’t exist.

#### Low Orphaned Post Meta / User Meta / Term Relationships

Meta rows pointing at deleted posts, users, or terms accumulated past the threshold (100 postmeta / 50 usermeta / 100 term-relationship rows).

##### Check

Three independent LEFT JOIN counts: postmeta vs posts, usermeta vs users, term\_relationships vs posts. Each fires when its threshold is exceeded.

##### Why it matters

Performance, not security. WordPress doesn’t always clean up child rows when a parent is deleted (especially older plugins / custom code), so an old, busy site accumulates orphans that bloat the database and slow down meta queries.

##### Fix

The Database Security page has a one-click **Clean Up** button for each of these (the finding has `fix_available = true`). The cleanup runs a `DELETE ... LEFT JOIN` on a 5-minute time limit / 256MB memory limit AJAX worker, which is safe on installs up to several hundred thousand orphans.

##### Safe to ignore

Yes, indefinitely. Orphaned meta is wasted space, not a security risk. If your install is performing fine and you don’t need to reclaim the bytes, skip the cleanup.

#### High / Medium Large Autoloaded Options

Total size of `autoload = 'yes'` rows in `wp_options` exceeds 1 MB (Medium) or 3 MB (High).

##### Check

`SELECT SUM(LENGTH(option_value)) FROM wp_options WHERE autoload = 'yes'`. Threshold-laddered.

##### Why it matters

WordPress loads every autoloaded option into memory on every single page request — including admin, REST, AJAX, and cron. A 3MB autoload payload adds a fixed cost to every request. The usual cause is a misbehaving plugin storing megabytes of cache / settings / logs as an autoloaded option instead of using transients or a custom table.

##### Fix

Identify the culprit. SSH into the database or use a query tool:

```
SELECT option_name, LENGTH(option_value) AS bytes
FROM wp_options
WHERE autoload = 'yes'
ORDER BY bytes DESC
LIMIT 20;
```

The top of the list is almost always one or two plugin-prefixed options. Identify the plugin (search plugin directory for the prefix), then either disable that plugin’s data-bloat feature or set the option to `autoload = 'no'` if it doesn’t need to be loaded on every request:

```
UPDATE wp_options SET autoload = 'no' WHERE option_name = '...';
```

##### Safe to ignore

Up to ~1MB is genuinely fine on modern hosting. Past 3MB it shows up as user-visible slowness. The High threshold corresponds to a real performance regression.

#### Low Expired Transients

More than 100 expired transient rows are sitting in `wp_options`.

##### Check

SQL count of `_transient_timeout_*` rows whose value (a UNIX timestamp) is less than `time()`.

##### Why it matters

WordPress lazy-deletes expired transients (only on the next read), so a site that writes a lot of transients but reads them rarely accumulates dead rows. Like orphaned meta — performance / cleanliness, not security.

##### Fix

One-click **Clean Up** on the Database Security page. Deletes all expired transient timeout rows AND all transient value rows (the cleanup is aggressive — clears expired and unexpired alike; legitimate transients will be regenerated on next access).

##### Safe to ignore

Yes. If the count stays in the low thousands, leave it; WordPress will eventually clean them up via its lazy-delete path.

#### Low Post Revisions

More than 500 post-revision rows exist in `wp_posts`.

##### Check

SQL count of posts with `post_type = 'revision'`.

##### Why it matters

WordPress stores a revision every time you save / autosave a post. On a site that’s been live for years with frequently-updated posts, revisions can easily outnumber published posts 10-to-1, bloating the database and slowing down post queries that JOIN against `wp_posts`.

##### Fix

1. One-click **Clean Up** on the Database Security page deletes ALL revisions in one query.
2. Cap future accumulation by adding `define( 'WP_POST_REVISIONS', 5 );` to `wp-config.php` — WordPress will then keep only the 5 most recent revisions per post.

##### Safe to ignore

Yes, if you actively use revision history to recover prior versions. The cleanup is destructive — once deleted, the prior versions are gone.

#### Low Spam Comments / Trashed Comments

More than 100 spam comments or more than 50 trashed comments in `wp_comments`.

##### Check

Two SQL counts: `comment_approved = 'spam'` (threshold 100) and `comment_approved = 'trash'` (threshold 50).

##### Why it matters

Akismet and equivalents catch spam comments and put them in the spam queue but don’t auto-delete them. Over months/years a busy comment site accumulates tens of thousands of spam rows that never get reviewed.

##### Fix

One-click **Clean Up** on the Database Security page, or empty the spam / trash queues from **WP Admin → Comments**.

##### Safe to ignore

Yes. Spam comments don’t affect the site; they just take up space.

#### Low Trashed Posts

More than 50 posts in the trash.

##### Check

SQL count of posts with `post_status = 'trash'`.

##### Why it matters

Same cleanup motivation as trashed comments. WordPress auto-deletes trashed posts after 30 days by default, but if you ever set `EMPTY_TRASH_DAYS` to 0 (disabled) or some plugin changed the value, trash accumulates indefinitely.

##### Fix

One-click **Clean Up**, or empty trash manually from **Posts → All Posts → Trash → Empty Trash**.

#### High Outdated MySQL Version

Your MySQL (or MariaDB compatibility layer) version is older than 5.7.

##### Check

`$wpdb->db_version()` compared with `version_compare` against `5.7`.

##### Why it matters

MySQL 5.6 and earlier no longer receive security updates from Oracle. Sites running them are accumulating unpatched database-server vulnerabilities at the engine level. Many newer WordPress features (and plugins) also assume 5.7+ behaviours (JSON columns, utf8mb4 indexes at full width, etc.) and silently degrade on older versions.

##### Fix

Upgrade via your hosting control panel. Most managed hosts offer MySQL/MariaDB version switching as a one-click option in cPanel / Plesk / WHM / the host’s dashboard. Take a backup first via [SiteVault Pro](https://royalplugins.com/sitevault/); in-place engine upgrades are normally safe but data-layer regressions exist.

##### Safe to ignore

No. The recommendation in the finding text targets MySQL 8.0+, but anything 5.7+ removes the High alert.

#### Critical Suspicious Post Content / Suspicious Options Data

Posts or non-transient `wp_options` rows contain code patterns consistent with injected malware.

##### Check

SQL LIKE scan against a curated pattern list covering: `eval(base64_decode(...))`, `eval(gzinflate(...))`, `eval(gzuncompress(...))`, `eval(str_rot13(...))`, `assert(base64_decode(...))`, `preg_replace` with the deprecated `/e` modifier, raw `<?php` tags inside post content, hidden / zero-dimension iframes, document.cookie exfiltration patterns, cryptominer references (coinhive, crypto-loot, coinimp, webminepool), and known shell signatures (c99shell, r57shell, WSO shell). Transient options are excluded to avoid false positives from cached page HTML.

##### Why it matters

These shapes are the signature of compromised WordPress installs. Attackers inject PHP into post content (so it executes when a page loads via filter callbacks that `eval()` shortcode-like content) or into the options table (so plugins that `maybe_unserialize` + `eval` trigger payload). Patterns are filterable via `guardpress_db_malware_patterns`.

##### Fix

This is a probable active compromise:

1. Take an immediate backup (do NOT overwrite a clean prior backup — you may need both)
2. Open the affected rows. The finding tells you whether it’s posts (`edit.php`) or options. For posts: review each, clean or delete. For options: identify the option name + the plugin that owns it; that plugin is likely the entry point
3. Run the full GuardPress malware scanner (**GuardPress → Malware Scanner**) on plugin / theme files to find the injection source
4. Rotate ALL passwords, salts, API keys

##### Safe to ignore

If you legitimately publish PHP code in posts (developer / tutorial blog), the post-content scan may false-positive on tutorials about `eval` or `base64_decode`. Filter the pattern list via `guardpress_db_malware_patterns` from a must-use plugin to remove the patterns that match your content. Don’t globally suppress — remove only the patterns that fire on your specific content.

#### Critical active\_plugins Option Corrupted / Contains Suspicious Entries

The `active_plugins` option in `wp_options` is not a normal serialized array of plugin paths.

##### Check

Two checks. (a) The option is read and verified to be an array; non-array = critical. (b) Each entry is verified to look like a plugin basename (matches `^([a-z0-9_.\-]+/)?[a-z0-9_.\-]+\.php$`), is not empty, contains no `base64_decode` / `eval(` / `<?php` / `..` / NUL bytes, and does NOT reference `mu-plugins/` (mu-plugins load automatically; they should never appear in active\_plugins).

##### Why it matters

Attackers who want to autoload injected code sometimes write malformed entries into `active_plugins` — bypassing the WP plugin loader’s normal validation. Any entry that doesn’t look like a real plugin path is either tampering or serious database corruption. Up to 5 example offending entries are included in the finding description.

##### Fix

Open **WP Admin → Plugins**. The deactivate/activate plugin list shows what WordPress thinks is active. Compare against the offending entries from the finding. Deactivate anything suspicious from the UI (which cleanly rewrites `active_plugins`). If the option is corrupted to the point that WP Admin won’t load, you may need to fix it directly via wp-cli: `wp option get active_plugins --format=json`, edit the JSON, `wp option update active_plugins '...'`.

##### Safe to ignore

Never. This is one of the highest-signal indicators of compromise the scanner produces.

#### Critical Poisoned Capability Metadata

Capability or `user_level` usermeta rows contain code-like patterns (eval / base64 /

##### Check

Same pattern list as the post / options content scan, applied to `usermeta` rows with `meta_key` matching `{prefix}_capabilities` or `{prefix}_user_level`. These rows should always be PHP-serialized arrays; code patterns indicate tampering.

##### Why it matters

Some role-escalation backdoors work by writing executable PHP into a capability row, then triggering deserialization of that row to `eval()` the payload.

##### Fix

Treat as active compromise; same response as “Suspicious Post Content” above.

#### High Recently Created Administrator Accounts

One or more accounts with the `administrator` capability were created in the last 30 days.

##### Check

SQL JOIN of `wp_users` + `wp_usermeta` for users with `{prefix}_capabilities LIKE '%administrator%'` and `user_registered > NOW() - 30 days`.

##### Why it matters

Stealth admin creation is a common post-compromise backdoor. Attackers create a low-profile admin account so that even after you clean up the obvious payload, they can log back in. A scheduled scan that surfaces brand-new admins for review catches this class.

##### Fix

Open **Users → Administrators**, sort by registration date, review each new admin. Anyone you didn’t personally invite should be deleted immediately, then rotate passwords + salts.

##### Safe to ignore

If your team genuinely onboarded a new admin recently (you know who, you invited them), confirm the account matches the expected user and move on.

#### High Admin Users Missing user\_level Metadata

A user has the administrator capability but no corresponding `user_level` usermeta row.

##### Check

SQL LEFT JOIN between the capabilities row (containing `administrator`) and the `user_level` row; counts where the level row is missing.

##### Why it matters

When WordPress assigns a role through its normal API, it writes BOTH the capabilities row and the user\_level row together. An admin-capable user with no user\_level row suggests the capability was injected directly into usermeta (bypassing the role API) — a stealth-admin pattern.

##### Fix

Investigate the user. If legitimate, re-save their role from **Users → Edit User** to repair the missing row. If unexpected, delete the account and follow the compromise response above.

#### Critical Suspicious Scheduled Cron Events

Scheduled WP-Cron hook names contain malware patterns or look injection-shaped.

##### Check

Walks `_get_cron_array()` and checks each hook name for substrings `base64_decode`, `eval(`, `<?php`, `gzinflate`, `str_rot13`, `shell_exec`, OR matches against a 24+ character pure-hex regex (which catches randomly-named hooks injected by automated payloads). Up to 5 example offending hook names are included in the finding.

##### Why it matters

WP-Cron is a common foothold — an attacker schedules a recurring event that re-introduces their payload on every run, defeating partial cleanup attempts. Detecting code-patterned hook names catches the most common shapes.

##### Fix

List your scheduled events: `wp cron event list`. Confirm the suspicious hook names are present. Delete each: `wp cron event delete <hook>`. Re-scan to confirm. Then investigate WHY a rogue hook was scheduled — the scheduler was a legitimate WP API call from compromised code somewhere.

##### Safe to ignore

Never. Code-patterned cron hook names are essentially diagnostic for compromise.

#### Low Zombie Cron Events

5 or more scheduled cron hooks have no registered listener.

##### Check

For each scheduled hook, `has_action($hook_name)` returns false — nothing is listening for it. Only surfaced when the unique zombie count is 5 or higher (1–4 zombies is normal from a recently-removed plugin and gets suppressed).

##### Why it matters

Plugins that uninstall poorly leave their scheduled events behind. The events fire forever, find nothing listening, and burn a small amount of work on every WP-Cron tick. Mostly hygiene, occasionally a tell that a plugin was force-deleted without going through proper deactivation.

##### Fix

`wp cron event list` to inspect, `wp cron event delete <hook>` to remove each.

##### Safe to ignore

Yes. Zombies don’t cause failures; they cost ~zero CPU each.

## One-Click Cleanup — Which Findings Support It

Findings with `fix_available = true` show a **Clean Up** button on the Database Security admin page. The button POSTs to the `guardpress_optimize_database` AJAX handler, which runs the deletion under a 5-minute time limit and 256MB memory budget. The handler covers:

- Orphaned post meta (`clean_orphaned_postmeta`)
- Orphaned user meta (`clean_orphaned_usermeta`)
- Orphaned term relationships (`clean_orphaned_terms`)
- Expired transients — also deletes all transient value rows (`clean_transients`)
- Post revisions (`clean_revisions`)
- Spam comments (`clean_spam_comments`)
- Trashed comments (`clean_trash_comments`)
- Trashed posts (`clean_trash_posts`)

Every cleanup is logged to the audit log as action `database_cleanup` with the count of items removed.

No undo

Cleanups are SQL DELETE statements with no soft-delete or recovery path. Take a backup before any cleanup you’re not 100% confident about — especially `clean_revisions` (irreversible loss of revision history) and `clean_transients` (deletes all transient values, expired or not).

## FAQ

### How often does the scan run?

Once a day on WP-Cron via the `guardpress_daily_scan` hook. You can also run it on demand via the **Run Scan Now** button. The on-demand path is registered unconditionally, so the button works even when the daily scheduled scan is toggled off.

### I’m getting a Critical “Suspicious Post Content” finding but I’m a developer blog and I publish code about `base64_decode` all the time

Filter the pattern list. Drop this into a must-use plugin:

```
add_filter( 'guardpress_db_malware_patterns', function( $patterns ) {
    // Remove the patterns that false-positive on legitimate code tutorials
    return array_values( array_filter( $patterns, function( $p ) {
        return strpos( $p, 'base64_decode' ) === false;
    } ) );
} );
```

Pare narrowly — remove only the patterns that fire on your real content. Don’t return an empty array; you’d disable the entire scan family.

### Why does GuardPress flag “Too Many Administrators” at 6 instead of some bigger number?

Heuristic. Most WordPress sites have 1–3 real admins and accumulated abandoned admin accounts. Six is the conservative cutoff where the typical site has a problem worth surfacing. Genuine multi-admin sites can ignore the finding — it’s Medium, doesn’t emit an alert email.

### What’s the difference between this and the Malware Scanner?

Database Security scans rows in the database for malware patterns. The standalone Malware Scanner (**GuardPress → Malware Scanner**) scans plugin / theme / uploads FILES on disk. Compromises usually have artifacts in both places, so a Critical finding from one should prompt running the other.

### Can I disable individual sub-checks?

Not via settings. The pattern lists (malware patterns in particular) are filterable via `guardpress_db_malware_patterns`, which lets you suppress specific patterns. The sub-check structure itself is fixed in code — if you have a use case for disabling a specific sub-check (e.g. orphaned-meta detection is irrelevant on a freshly-imported site), email priority support and we’ll consider adding a filter.

## Still Stuck? Email Priority Support

If a finding doesn’t match anything in this reference, or you’re trying to decide whether to act on a Critical finding for your specific situation:

Email **[support@royalplugins.com](mailto:support@royalplugins.com)** with the diagnostic info below. Priority email support is included with your GuardPress Pro license — typical response time is within 24 hours.

#### Information to include in your email

- **GuardPress version** from **WP Admin → Plugins** (1.6.10 or higher for the full malware / tampering check family)
- **WordPress version** from **WP Admin → Updates**
- **The exact finding name and severity** from **GuardPress → Database**
- **The finding description text** as it appears in the report (so we can tell which sub-check it came from and which threshold was crossed)
- **For Critical malware findings:** whether you’ve already taken a backup, and whether the site has recently shown other compromise indicators (file integrity alerts, unexpected admin notices, weird outbound traffic, customer reports of redirects)
- **What you’ve already tried** — especially if a one-click cleanup finished but the finding persists
- **Hosting setup** — managed (SiteGround, Kinsta, WP Engine) vs shared (Bluehost, HostGator) vs VPS — matters for some MySQL-upgrade and shell-access recommendations

Related GuardPress topics

Database Security overlaps with several other GuardPress modules:

- [**Vulnerability Scanner — What Each Finding Means**](https://royalplugins.com/support/guardpress/outdated-software-check-explained/) — sister reference for the other recurring scan
- [**File Integrity Alert Investigation**](https://royalplugins.com/support/guardpress/file-integrity-alert-investigation/) — if Critical database findings led you to look at file-level integrity
- [**Quieting Security Alert Email Flood**](https://royalplugins.com/support/guardpress/quieting-security-alert-emails/) — if Critical/High findings are emailing you every day
- [**Database Security overview**](https://royalplugins.com/support/guardpress/#database-security) — the short feature description on the main GuardPress support page
- [**SiteVault Pro**](https://royalplugins.com/sitevault/) — for backups before running cleanup actions

[Back to GuardPress Support](https://royalplugins.com/support/guardpress/)
[GuardPress Plugin Page](https://royalplugins.com/guardpress/)
