{"id":11793,"date":"2026-08-29T16:05:57","date_gmt":"2026-08-29T08:05:57","guid":{"rendered":"https:\/\/aeosub.com\/leanroles\/"},"modified":"2026-08-29T16:05:57","modified_gmt":"2026-08-29T08:05:57","slug":"leanroles","status":"publish","type":"post","link":"https:\/\/aeosub.com\/zh\/leanroles\/","title":{"rendered":"LeanRoles \u2013 User Tags &amp; Role Performance Audit"},"content":{"rendered":"<div class=\"post-img\" style=\"margin-bottom: 25px\"><img decoding=\"async\" src=\"https:\/\/ps.w.org\/leanroles\/assets\/banner-1544x500.png?rev=3665616\" alt=\"LeanRoles \u2013 User Tags &amp; Role Performance Audit\" loading=\"lazy\" style=\"width: 100%;height: auto;border-radius: 12px\"><\/div>\n<div class=\"plugin-expert-review\" style=\"border: 1px solid #e2e8f0;border-left: 4px solid #4a3bca;border-radius: 10px;padding: 20px;margin-bottom: 25px;background: #fff;font-family: -apple-system, system-ui, sans-serif\">\n<div style=\"font-weight: bold;font-size: 1.1em;color: #4a3bca;margin-bottom: 10px\">LethaldiranMX Insight<\/div>\n<div style=\"color: #4a5568;font-size: 14px;line-height: 1.6\">\n<div>\n<p>LeanRoles addresses a critical, often overlooked architectural bottleneck in high-traffic WordPress membership and e-commerce platforms: the memory and CPU overhead caused by bloated, autoloaded user role configurations. By auditing the real-world cost of the wp_user_roles option and introducing a lightweight &#8220;User Tags&#8221; primitive, it prevents PHP workers from wasting cycles unserializing massive capability arrays on every logged-in request. It is an exceptionally elegant, developer-centric solution to WordPress core&#8217;s lack of role inheritance and its inefficient storage of user permissions.<\/p>\n<p><strong>Best Fit &amp; Operational Role:<\/strong> This plugin is an essential diagnostic and optimization tool for enterprise WooCommerce installations, complex membership sites, and large-scale digital operations running dozens of custom roles. It fits directly into the performance-tuning layer of the WordPress stack, allowing systems engineers to replace empty or purely organizational roles with memory-efficient tags that still hook seamlessly into standard APIs like current_user_can() and WP_User_Query without bloating the database.<\/p>\n<p><strong>Potential Limitations &amp; Pitfalls:<\/strong> While the auditing engine is strictly read-only and highly optimized, the integration of Freemius for licensing and updates introduces an external third-party dependency that security-conscious enterprise environments must vet. Additionally, because custom code often checks capabilities dynamically, developers must carefully interpret the auditor&#8217;s &#8220;unrecognised&#8221; capability flags to avoid deprecating roles that are queried by proprietary plugins or bespoke integrations.<\/p>\n<\/div>\n<\/div><\/div>\n<div class=\"plugin-info-card\" style=\"border: 1px solid #e2e8f0;border-radius: 10px;overflow: hidden;margin-bottom: 30px;font-family: -apple-system, system-ui, sans-serif;background: #fff\">\n<div style=\"padding: 20px;border-bottom: 1px solid #edf2f7;background: #fafafa;display: flex;align-items: flex-start\">\n                <img decoding=\"async\" src=\"https:\/\/ps.w.org\/leanroles\/assets\/icon.svg?rev=3665588\" alt=\"LeanRoles \u2013 User Tags &amp; Role Performance Audit icon\" loading=\"lazy\" style=\"width: 45px;height: 45px;border-radius: 8px;margin-right: 15px\"> <\/p>\n<div style=\"flex: 1;line-height: 1.2\">\n<div style=\"font-weight: bold;font-size: 1.1em;color: #1a202c\">Plugin Specification<\/div>\n<p>                    <small style=\"color: #718096\">WordPress.org Official Data<\/small>\n                <\/div>\n<\/p><\/div>\n<table style=\"width: 100%;border-collapse: collapse;font-size: 14px\">\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;width: 35%;color: #4a5568;background: #fcfcfc\">Developer<\/th>\n<td style=\"padding: 12px 20px;font-weight: 500\"><a href=\"https:\/\/profiles.wordpress.org\/davefx\/\" target=\"_blank\" rel=\"noopener\">David Mar\u00edn Carre\u00f1o (DaveFX)<\/a><\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Version<\/th>\n<td style=\"padding: 12px 20px\">v0.6.1<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Active Installs<\/th>\n<td style=\"padding: 12px 20px\">0 +<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Requires \/ Tested<\/th>\n<td style=\"padding: 12px 20px\">5.9 \/ 7.1<\/td>\n<\/tr>\n<tr style=\"border-bottom: 1px solid #edf2f7\">\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Last Updated<\/th>\n<td style=\"padding: 12px 20px\">2026-08-29 8:05am GMT<\/td>\n<\/tr>\n<tr>\n<th style=\"padding: 12px 20px;text-align: left;color: #4a5568;background: #fcfcfc\">Official Link<\/th>\n<td style=\"padding: 12px 20px\"><a href=\"https:\/\/wordpress.org\/plugins\/leanroles\/\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"text-decoration: none;color: #4a3bca;font-weight: bold\">View Details -&gt;<\/a><\/td>\n<\/tr>\n<\/table><\/div>\n<div class=\"plugin-short-desc\" style=\"margin: 20px 0;padding: 12px 15px;background: #f9fafb;border-left: 4px solid #4a3bca;border-radius: 6px;font-style: italic;color: #4a5568\">Audits what your user roles cost on every request, and adds user tags: label users without creating roles that grant nothing and weigh nothing.<\/div>\n<p>WordPress keeps every role in one autoloaded option, with each role&#8217;s capabilities copied out in full, because core has no inheritance. On a membership or commerce site with forty roles that option is read, unserialized and held in memory by every PHP worker on every request \u2014 and those are exactly the sites whose traffic is mostly logged in, so page caching never gets a look in.<\/p>\n<p>LeanRoles does two things about it.<\/p>\n<p><strong>It measures.<\/strong> The auditor is strictly read-only. It takes the size of your role option with <code>LENGTH()<\/code> in the database rather than re-serializing it in PHP, times a real <code>unserialize()<\/code> of it on your machine after a warm-up pass, measures the resident footprint with the result kept alive, and works out what that costs in concurrent workers. It identifies roles that grant no effective permission, roles nobody holds, roles with identical capability sets, and capabilities it cannot account for \u2014 while being explicit that &#8220;unrecognised&#8221; is not &#8220;orphaned&#8221;, because custom code checks capabilities no scanner can see.<\/p>\n<p><strong>It offers the missing primitive.<\/strong> There is no way in WordPress to say &#8220;this user is a wholesale customer&#8221; without granting them permissions. There are only roles. That is why membership plugins keep inventing them: they have no alternative. A LeanRoles tag is that alternative. It appears in <code>$user-&gt;roles<\/code>, answers <code>current_user_can()<\/code>, and can be filtered on in <code>WP_User_Query<\/code> \u2014 and it is never written to the autoloaded option. Third-party code cannot tell the difference.<\/p>\n<h4>What it does<\/h4>\n<ul>\n<li>The auditor, with real measurements and <code>wp leanroles audit --format=json<\/code><\/li>\n<li>User tags: create, assign individually or in bulk, filter, a users-list column, CSV import and export<\/li>\n<li>The tag engine as a standalone library, <code>libraries\/user-tags\/<\/code>, that any plugin can bundle so tags cost them nothing to adopt<\/li>\n<li>WP-CLI: create a tag, assign it in bulk by role, edit or delete a role with reassignment, move a role configuration between sites, take and restore role-option backups<\/li>\n<\/ul>\n<h4>Licensing, and the one external service<\/h4>\n<p>LeanRoles uses <a href=\"https:\/\/freemius.com\" rel=\"nofollow ugc noopener\" target=\"_blank\">Freemius<\/a> for licensing, payment and automatic updates on its paid plan. Freemius is a third-party service, and this is the only thing in the plugin that talks to anything outside your site.<\/p>\n<p><strong>Nothing is sent anywhere unless you say so.<\/strong> The plugin asks once, on activation, and skipping is a real option: skip it and the plugin works exactly as it does otherwise. Nothing about the auditor or user tags depends on it.<\/p>\n<p>If you do opt in, what is shared is:<\/p>\n<ul>\n<li>your WordPress user&#8217;s name and email address;<\/li>\n<li>the site&#8217;s homepage URL and title, its language, and the WordPress and PHP versions;<\/li>\n<li>which version of LeanRoles is running, its SDK version, and whether it is active or has been uninstalled.<\/li>\n<\/ul>\n<p>Two further items are optional and stay off unless you tick them: the list of other plugins and themes installed on the site, and the newsletter.<\/p>\n<p>Activating a licence key sends the key and the site URL, so the licence can be checked and updates delivered to you.<\/p>\n<p>Freemius&#8217; <a href=\"https:\/\/freemius.com\/terms\/\" rel=\"nofollow ugc noopener\" target=\"_blank\">terms<\/a> and <a href=\"https:\/\/freemius.com\/privacy\/\" rel=\"nofollow ugc noopener\" target=\"_blank\">privacy policy<\/a> cover what they do with it.<\/p>\n<p><a href=\"https:\/\/davefx.com\/en\/wordpress-plugins\/leanroles\/\" rel=\"nofollow ugc noopener\" target=\"_blank\">What the paid plans cost, and what they add<\/a><\/p>\n<h4>What it does not do<\/h4>\n<p>It does not convert roles into tags for you. What it gives you are three independent primitives \u2014 create a tag, assign it in bulk, delete a role with reassignment \u2014 which compose into a conversion done by hand, by someone who has read the audit and accepts the risk.<\/p>\n<p>Before deleting a role it tells you how many capabilities that role grants and how many users hold it. It does not tell you which of those users will actually notice the difference: answering that means computing effective capabilities per user, before and after, and the plugin does not do it. Take a backup and check for yourself.<\/p>\n<h3>Development<\/h3>\n<p>The distributed plugin has no dependencies and no build step: what is in <code>src\/<\/code> and <code>assets\/<\/code> is what runs. Composer is used only for the test suite, and <code>.distignore<\/code> keeps all of it out of the release.<\/p>\n<pre><code>composer install\n.\/tests\/bin\/start-db.sh      # throwaway MariaDB on 127.0.0.1:3307\n.\/tests\/bin\/install.sh       # WordPress + the test library\ncomposer test                # single site\ncomposer test:multisite      # network\ncomposer test:matrix         # WordPress 5.9, 6.5 and latest\ncomposer lint                # standards + PHP 7.4 compatibility\n<\/code><\/pre>\n<p>Every test runs against a real WordPress install and a real database, because the risky parts of this plugin are all seams it does not own \u2014 the short-circuit contract of the metadata filters, what <code>WP_User::set_role()<\/code> does on its way past, how <code>WP_User_Query<\/code> builds a role clause. See <code>tests\/README.md<\/code>.<\/p>\n<div class=\"plugin-editorial-note\" style=\"margin-top: 25px;padding: 12px 15px;background: #f8fafc;border-radius: 6px;color: #64748b;font-size: 13px;line-height: 1.5\">Editorial note: This overview combines WordPress.org official plugin metadata with an AI-assisted LethaldiranMX editorial review. Plugin data should be verified on the official WordPress.org listing before installation.<\/div>","protected":false},"excerpt":{"rendered":"<p>Audits what your user roles cost on every request, and adds user tags: label users without creating roles that grant nothing and weigh nothing.<\/p>","protected":false},"author":1,"featured_media":11794,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[252],"tags":[2499,1847,2357,1403,3025,555],"class_list":["post-11793","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-trends","tag-capabilities","tag-multisite","tag-user-management","tag-user-roles","tag-user-tags","tag-wordpress-plugin"],"_links":{"self":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/posts\/11793","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/comments?post=11793"}],"version-history":[{"count":0,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/posts\/11793\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/media\/11794"}],"wp:attachment":[{"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/media?parent=11793"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/categories?post=11793"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aeosub.com\/zh\/wp-json\/wp\/v2\/tags?post=11793"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}