{"id":313382,"date":"2026-05-18T20:47:50","date_gmt":"2026-05-18T20:47:50","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/headless-login-guard\/"},"modified":"2026-05-18T20:47:28","modified_gmt":"2026-05-18T20:47:28","slug":"headless-login-guard","status":"publish","type":"plugin","link":"https:\/\/test.wordpress.org\/plugins\/headless-login-guard\/","author":5066873,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"1.0.1","stable_tag":"1.0.1","tested":"6.9.4","requires":"6.0","requires_php":"8.1","requires_plugins":null,"header_name":"Headless Login Guard","header_author":"Andrew Wilkinson","header_description":"Forces login for backend access in headless WordPress setups while allowing GraphQL\/REST API endpoints and essential paths.","assets_banners_color":"000000","last_updated":"2026-05-18 20:47:28","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/MeonValleyWeb\/headless-login-guard","header_author_uri":"https:\/\/meonvalleyweb.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":31,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.1":{"tag":"1.0.1","author":"andrew40","date":"2026-05-18 20:47:28"}},"upgrade_notice":{"1.0.1":"<p>This version adds WordPress.org compatibility and developer customization options. Safe to upgrade.<\/p>"},"ratings":{"1":0,"2":0,"3":0,"4":0,"5":0},"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3536307,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3536307,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3536308,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3536308,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.1"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"The Force Login plugin requires no configuration - just activate and it works immediately","2":"Attempting to access \/wp-admin while logged out redirects to the login page","3":"After logging in, the WordPress dashboard is fully accessible"},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[175418,141196,602,23853,600],"plugin_category":[38,54],"plugin_contributors":[263429],"plugin_business_model":[],"class_list":["post-313382","plugin","type-plugin","status-publish","hentry","plugin_tags-graphql","plugin_tags-headless","plugin_tags-login","plugin_tags-rest-api","plugin_tags-security","plugin_category-authentication","plugin_category-security-and-spam-protection","plugin_contributors-andrew40","plugin_committers-andrew40"],"banners":{"banner":"https:\/\/ps.w.org\/headless-login-guard\/assets\/banner-772x250.png?rev=3536308","banner_2x":"https:\/\/ps.w.org\/headless-login-guard\/assets\/banner-1544x500.png?rev=3536308","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/headless-login-guard\/assets\/icon-128x128.png?rev=3536307","icon_2x":"https:\/\/ps.w.org\/headless-login-guard\/assets\/icon-256x256.png?rev=3536307","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>A lightweight plugin that <strong>forces login for backend access<\/strong> in a headless WordPress setup. Keeps your WordPress dashboard private while allowing your front end (e.g. Astro, Next.js) to pull content via GraphQL\/REST.<\/p>\n\n<h4>What it does<\/h4>\n\n<ul>\n<li>Requires authentication for <code>\/wp-admin\/<\/code> and other backend pages<\/li>\n<li>Always allows the login page to avoid redirect loops<\/li>\n<li>Leaves key endpoints open for headless use:\n\n<ul>\n<li><code>\/wp-json\/<\/code> (REST API)<\/li>\n<li><code>\/graphql<\/code> (WPGraphQL)<\/li>\n<li><code>\/wp-admin\/admin-ajax.php<\/code> (AJAX)<\/li>\n<li><code>\/wp-cron.php<\/code> (cron)<\/li>\n<li><code>\/robots.txt<\/code><\/li>\n<li><code>\/sitemap*.xml<\/code> (sitemaps and indexes)<\/li>\n<li><code>\/wp-content\/uploads\/*<\/code> (media)<\/li>\n<li><code>\/favicon.ico<\/code><\/li>\n<li><code>\/newrelic<\/code> (New Relic monitoring)<\/li>\n<\/ul><\/li>\n<li>Logged-in users visiting the backend root get redirected to the dashboard<\/li>\n<li>Works with Bedrock layouts (handles root path vs <code>\/wp\/<\/code>)<\/li>\n<\/ul>\n\n<h4>Use case<\/h4>\n\n<ul>\n<li>WordPress is the content backend<\/li>\n<li>Public site is built with Astro\/Next.js\/etc<\/li>\n<li>Editors log in to WordPress. Visitors never see the backend<\/li>\n<li>Front end builds and live pages can still query GraphQL\/REST without authentication<\/li>\n<\/ul>\n\n<h4>Customization<\/h4>\n\n<p>Developers can customize allowed endpoints using the <code>force_login_allowed_patterns<\/code> filter:<\/p>\n\n<pre><code>add_filter('force_login_allowed_patterns', function($patterns) {\n    $patterns[] = '#^\/healthz$#';           \/\/ custom health check\n    $patterns[] = '#^\/status$#';            \/\/ uptime checks\n    $patterns[] = '#^\/wp-json\/acf\/v3\/.*#';  \/\/ specific REST namespace\n    return $patterns;\n});\n<\/code><\/pre>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin files to the <code>\/wp-content\/plugins\/force-login<\/code> directory, or install the plugin through the WordPress plugins screen directly.<\/li>\n<li>Activate the plugin through the 'Plugins' screen in WordPress.<\/li>\n<li>The plugin will automatically start protecting your backend - no configuration needed!<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"i%27m%20locked%20out%21%20how%20do%20i%20access%20my%20site%3F\"><h3>I'm locked out! How do I access my site?<\/h3><\/dt>\n<dd><p>Visit <code>\/wp-login.php<\/code> directly to sign in. The plugin always allows access to the login page.<\/p><\/dd>\n<dt id=\"my%20front-end%20requests%20are%20failing.%20what%20should%20i%20do%3F\"><h3>My front-end requests are failing. What should I do?<\/h3><\/dt>\n<dd><p>Verify the endpoint is on the allow list. Check the plugin description for the default allowed patterns, or use the <code>force_login_allowed_patterns<\/code> filter to add custom endpoints.<\/p><\/dd>\n<dt id=\"does%20this%20work%20with%20bedrock%3F\"><h3>Does this work with Bedrock?<\/h3><\/dt>\n<dd><p>Yes! The plugin correctly handles both standard WordPress installs and Bedrock layouts where the site URL and home URL may differ.<\/p><\/dd>\n<dt id=\"can%20i%20add%20custom%20endpoints%3F\"><h3>Can I add custom endpoints?<\/h3><\/dt>\n<dd><p>Yes, use the <code>force_login_allowed_patterns<\/code> filter to add your own regex patterns for additional endpoints that should remain public.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Added: New Relic monitoring endpoint allowlist pattern (<code>\/newrelic<\/code>) to support APM monitoring<\/li>\n<li>Added: WordPress.org plugin directory compatibility<\/li>\n<li>Added: Proper plugin structure with activation\/deactivation hooks<\/li>\n<li>Added: Filter hook for customizing allowed patterns<\/li>\n<li>Improved: Code organization and documentation<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>Restricts backend (<code>\/wp-admin\/<\/code>) to authenticated users<\/li>\n<li>Allows GraphQL and REST API endpoints for headless front-ends<\/li>\n<li>Basic whitelist of essential endpoints (cron, ajax, robots.txt, sitemaps, uploads)<\/li>\n<\/ul>","raw_excerpt":"Forces login for backend access in headless WordPress setups while allowing GraphQL\/REST API endpoints and essential paths.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/313382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=313382"}],"author":[{"embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/andrew40"}],"wp:attachment":[{"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=313382"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=313382"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=313382"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=313382"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=313382"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/test.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=313382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}