Hugo behind paywall/membership : conditional rendering

I’m almost done completing my migration of WordPress server-side SQL views blogs to Hugo, and the last remaining step is migrating those membership-based ones. The architecture I have in mind is this:

  • private_html/
    • 404.html
    • non-members/ → Hugo-rendered website
    • members/ → Hugo-rendered website
  • public_html/
    • .htaccess
    • index.php
    • login.php
    • subscribe.php
    • account.php

.htaccess would handle URL rewriting to index.php:

RewriteEngine On
RewriteBase /
# Redirect all traffic to index.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ index.php [QSA,L]

index.php would do the triage:

// Get the full URL before redirection by .htaccess
$parsed_url = parse_url($_SERVER['REQUEST_URI']);

// Separate domain from path
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '/';

$PUBLIC = '../public_html/non-members';
$PRIVATE = '../public_html/members';

$is_logged_in = is_valid($_COOKIE["token"]);

// Redirect the path to the static website pages
switch($path) {
  // PHP endpoints
  case "/login.php":
  case "/account.php":
  case "/subscribe.php":
    require_once($path);
    break;

  // Regular pages
  default:
    $member_target = $PRIVATE . $path . 'index.html';
    $nomember_target = $PUBLIC . $path . 'index.html';

    if($is_logged_in && file_exists($member_target))
      require_once($member_target);
    else if(file_exists($nomember_target))
      require_once($nomember_target);
    else
      require_once('../public_html/404.html');
    break;
}

Now, given that Hugo doesn’t seem to have ways of producing content alternatives, I’m thinking of using a shortcode that would output the full page content if some compilation flag is set, otherwise a truncated content or notification message. Then, private_html/members and private_html/non-members would each have the full website, one compiled with full content, the other with the truncated content.

Question is: how can I map a shortcode output to a custom building flag ?

Or is it a better way ?

Netlify provides a (paid) feature for password/membership protected sites:

Thanks but that’s obviously not what I’m after. I want stuff that works on regular LAMP servers and can be moved in the future to any other LAMP server. Also, no way I’m going to host anything that matters in Trumperica, I want my servers in Europe.

So I guess, the path of least resistance is to use config environments, have a _default one with common options, then a members and a nomembers ones which declare some [Site.Parameters] boolean key, and have content respond to this boolean. Then build with hugo -e members or hugo -e nomembers.

And for user management, https://www.userfrosting.com/ seems KISS enough.

No disrespect, but wouldn’t it just be easier to use a CMS? I love Hugo, but it’s not always the best choice.

3 Likes

Yes, it would be easier to have a CMS. That’s what I have now.

Then, you would have to install some plugin on said CMS to support Markdown syntax, then another to add auto table of contents. That’s assuming the CMS content editor doesn’t mess up and/or second-guess your syntax.

Then you would have to install a SEO plugin to get proper metadata in <head> and produce a sitemap.xml, because very few CMS have that in core. You need a way to discard those taxinomies archive pages from there, because they duplicate contents as for as search engine are concerned.

Then you would need to find a theme that looks reasonably close to what you want and is not coded with the butt, that is loading lots of static files even though you don’t use them. If you don’t find one, then you would have to design your own theme, but while Hugo lets you theme & template stuff as you need them, CMS need to have many endpoints covered from the start. Or you could use one of “page builder” themes that are slow in your browser, heavy on your server, and break every next update.

Then you would need a way to figure out multilanguage, because that has been a second thought in pretty much all CMS, so here you go, stacking crappy plugins on top of crappy plugins, hoping they play nice with each other (they won’t).

Then, of course, since all that is heavy on the server, you need a caching system. One that plays nice with all the aforementionned plugins, but again, very few CMS have that in core, so it’s another third-party plugin. Plugin’s user support love nothing more than blaming the caching plugin for everything remotely affecting their product, it’s never them.

Finally, you would need to mind the garbage collection in your database : multilinguage duplicates content, but duplicates metadata too, plus adds lots of stuff. Plugins you de-install don’t necessarily clean up after themselves. Neither do logs. One day you wake up, your 120-pages blog has a database of 600 MB, and you wonder why.

Not to mention, a dynamic CMS is a living organism that you need to keep updated all the time, for safety. But then, updates will create new bugs and incompatibilites, so you have to commit forever into maintaining it, the funniest part is it will break when you have the least amount of time to fix (Murphy’s law).

So, no its not easier with a CMS. Hugo does all the above in core. It’s no big deal scripting custom stuff in Hugo. Your Hugo scripts will have zero security issue for obvious reasons. It’s like doing LaTeX in your browser. If a future Hugo version breaks older templates, you just re-download the previous 80 MB Go package known to work, put it in your project directory, and keep building with that. You don’t even need it system-wide.

All the CMS-y part needed is a thin layer of PHP acting as firewall on top and directing users to a variant of the website based on the value of some cookie.


PS: I didn’t even mention responsive image sizes support or account security…

Think maybe you should look at something other than Wordpress. I have none of the problems you describe.

What CMS are you using ?

Craft, mostly.

1 Like