Categories
Uncategorized

ClassicPress is Losing

This site runs ClassicPress, the fork of WordPress that does not include the Block Editor crap. I also have been running a clone of site for my full-time job that I converted to ClassicPress. We make use of GravityForms and several 3rd party add-ons for GravityForms for many, many online forms there. Recently an update to GravityForms broke the ClassicPress Dashboard on my clone site. That pretty much seals its fate for use where I work full-time. If ClassicPress doesn’t get a majority of these big-name plugin and theme developers on board supporting their platform instead of or as well as WordPress, ClassicPress is doomed to wither on the vine.

Categories
Uncategorized

Scandroid

Back in the day, I found an industrial rock project called Circle of Dust.  Fast forward a couple decades, and I re-found the guy behind Circle of Dust in his latest projects that hit a sweet spot with me, because, yes, I do like retro 80’s synthwave.  Check out Scandroid on Bandcamp if you’re into that.

Speaking of retro and of recommendations, for the past few years I’ve been suffering through a midlife crisis. I’ve come to think that there is nothing nor anyone who can really help you through a midlife crisis, because everyone’s past experiences and present situation is different. I read what helps other people and why, and I think, “but, actually, in my case the why is flipped, and that what really isn’t applicable.”  Sometimes it isn’t flipped, by the way, I’m just thinking of one thing in particular as I write this, but even if it isn’t flipped, it’s at least skewed, and still not helpful.

Anyway, what does help me in general through difficult things is to better understand it.  While understanding it hasn’t helped much in actually finding a way to end my midlife crisis, it has helped in coping with it to some degree.  And what really helped me understand it was this book: In Midlife by Murray Stein, maybe because when it comes to psychology, I’m more of a Jungian man myself.  Stuff out of the Jungian school seems more pragmatically flexible and applicable to me.  I also like to write stories, so archetypes are a nice way to get at characters and conflict, so maybe that’s why, too.  I like to think, though, that it is because I’m brilliant.  I digress.

I also had a dream that was clearly about my midlife crisis and also kind of led me to that book — in the dream I first encountered Zeuss (yes, that incorrect spelling) and was led to a kind of neoplatonist cult… uh… service, that was more like a Baptist tent revival in the dark, after riding around in a car with some dead people as well as an actual former neoplatonist I know, all of whom had been significant in some way in my life.  Those ancient polytheistic pantheons are full of archetypes, so I suppose that, combined with the dream, is why I ended up on a Jungian book to help me grapple with myself in midlife.  I think Jung developed a lot of his theories out of his own midlife crisis struggles, and I think he was really onto some things that help in understanding it, so … that book.

I took Psych 101 in college about 33 years ago, and so that makes me a citable  authority in psychology if you need to reference this post.

Categories
Uncategorized

Hey, hey!

The last Classic Press update fixed the home page setting problem I mentioned in a previous blog entry.  Way to go, guys!

Categories
Uncategorized

ClassicPress

The “block editor” in WordPress leaves a lot to be desired, IMO.  The WordPress people are also pushing the concept into layout, which me and a lot of other folks aren’t happy about.  There’s a project out there called ClassicPress that is a fork of the last WordPress code that did NOT contain the block editor.  I definitely noticed that it responds faster to hits than the current getting-bloated WordPress.

Anyway, I switched this site to ClassicPress to see how it goes.  So far the only problem I’ve hit is that it doesn’t seem to acknowledge the static home page setting. It goes straight to the blog roll page always. I suspect a couple possibilities that I could maybe work around.

Categories
Uncategorized

Concrete5 Development is a Nightmare

A recent client has a website built on Concrete5. I’d first run across Concrete5 (C5) about a dozen years ago when I was evaluating free, open source content management systems for my employer. I installed and tinkered with more than half a dozen. We were determining a best-fit for consolidating an unruly number of websites on various platforms down to as a few as possible.

I can’t remember specifically why I eliminated Concrete5 from the list of many solutions I looked at, but I recall the major concerns to be addressed were:

  • Ease-of-use by people in business units
  • Support for importing content from other content systems in use
  • Rapid development of extensions

WordPress, by the way, easily won out over the competitors as a best fit for us at the time, and it probably still is the best fit.

Now, in 2021, I come across Concrete5 again. It’s apparently gone through a lot since then, but it still wouldn’t win the battle of the CMS’ for best fit for that employer. It might win out for ease-of-use. Or it might not: people there don’t like the WordPress block editor, even once they get used to it, and the C5 editor feels kinda the same to me.

For me, the paramount concern is ease of extending, which comes down to three things for community built and supported software:

  • Developer documentation in the form of guides and API references with plenty of examples.
  • Good community knowledgebase — forums or ticket systems with solutions, etc. — with good search and filtering capabilities
  • Consistent, simple design and architecture

Concrete5 fails in all those areas. In general it fails in all those areas because all the resources mix very, very old retired content with current content. You search, you find a solution, and then discover the information is actually 5, 6, or more years old, or applies only to a long-dead previous system design. Or you find an older solution that still works, but then later discover those features have been deprecated (maybe for years without actually being removed).

The C5 design is very loosely based on a model-view-controller (MVC) architecture. I generally like the MVC pattern, but I think it’s awful for open-source, web development for a number of reasons I’ll leave for another (maybe) post. In short, the MVC pattern isn’t definitively prescriptive — it is just a pattern, after all — and so every implementation I’ve come across is nuanced and different in its interpretation of the pattern. That makes a particular implementation particularly (heheh!) difficult to pick up quickly. That, as well as the other usual problems with MVC open source web software, shines in C5, and shines ever more brightly because the documentation is so terribly bad.

And the documentation’s near-total failure might be the thing that most makes C5 development nightmarish. Some pages that I have found that were really good in covering an obsolete version have no equivalent page for the current version. Some of the pages are just downright incomplete. Others are just … wrong. Here’s an example from the page on how to put a CSRF token in your form and validate it:

The astute, and even the not so astute, reader will notice that the sample code never invokes the output() method. If you enter what they have there, you’ll get nothing on your page, and in fact, will likely get an error because there should be a \ in front of Core::. Even if it does run, generate doesn’t emit anything. To do what they describe, you need this line instead:

\Core::make('token')->output('perform_change_password');

They don’t fix it in later copies of the example, either.

It would be one thing if I’d had to go looking for an example of a problem with the documentation, but I didn’t. That just happened to be open in my browser because adding a CSRF token to my forms was the thing I was working on when I was writing this post. That’s just how frequently flawed the documentation is: you can just open a page at random, close your eyes, and point. OK, that’s exaggerating (but not much).

The API reference (auto-generated doc pages) is so bad that even when a method is documented, what is said about it is virtually useless. Here’s a screenshot of something I looked at today as just a close-your-eyes-and-point example:

I was looking up the action() API. I got to the end of the description and asked out loud, “In the context of what?” I was alone in the room, so no one answered me.

But look at the rest of all that, too! Most methods have no documentation whatsoever, and even when they do their parameters don’t, and even when they do, it’s often just re-iterating the name, telling you nothing about exactly what the name means, the types, whatever. So then you go code spelunking. Let’s just look at that action() method:

Lo and behold! It actually can take more than one argument! Who knew? Yet it doesn’t. Sort of — I mean, it says there is one it refers to in the comment as $task, but nothing called $task is ever used. One would presume it would be passed in the open-ended argument list that the $controllerPath value is prepended to, but is it required if you are going to pass through more opaque values to your handler (assuming it does that “in the context of.” or maybe even outside “the context of.”)? It’s also pretty neat how the description says “… with a task and optional parameters…” and makes no mention of an “action,” and yet $action is the only explicit argument and how that differs from $task or what $task might be isn’t even addressed. I guess to find out, I can just go look at that thing it is calling near the end there, with [$this,’url’]. If you don’;t know, that’s how you would call a method named ‘url’ on an instance of the class we are looking at, so back to the documentation for View to see what that says about the url() method:

Oh. It’s deprecated. Huh. Regardless, you use it in a view to generate URLs with tasks and parameters. And actions, whatever they are “in the context of.” Not really helpful, so we look at the code again, and ….

Huh. It just goes off and does another call to a static member in a different class. Note that I still haven’t really learned much of anything about the action() method, except that it’s a method of lightspeed skipping through code (reference to a movie script written as badly as the C5 docs). Incidentally, this is just after that url() function in the code:

I’m not sure what that “// Legacy Items. Deprecated” refers to … hopefully not the stuff that follows, because there are no more comments until the last function in the file, and all the intervening stuff looks pretty important.

At this point, I really don’t care anymore about the details of the action() method. Trial and error would be quicker. But for grins and giggles, let’s go find that URL::to() method being called by the url() method. I’ve been looking at info for class View in the Concrete\Core\View namespace. There’s no URL class that I see in that namespace, so I’ll pop up a level to Concrete\Core. Ah, there is a Url class in there … oh, but wait, it has no to() method, and when I click to view its source, I get directed to a 404 page, and that’s when I notice the case is wrong in the name anyway. Silly me. So, I’ll search the API docs. That doesn’t turn up anything with only capital letters. Some time later unsuccessfully trying to locate that class in the documentation — I’ll spare you the boring details — I’m beginning to think I imagined seeing it, so back to the code I go. This time, since I have C5 installed locally, I just grep -r ‘class URL’ * on my computer at the root of the C5 install directory. I’ll spare you those gory details, too, of winding up down in concrete/vendor/illuminate/support/Facades/URL.php, where I find this trinket:

<?php

namespace Illuminate\Support\Facades;

/**
 * @see \Illuminate\Routing\UrlGenerator
 */
class URL extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'url';
    }
}

That is the totality of the code file right there. It’s a hook into the Laravel framework (which I really don’t know much of anything about, to be honest). At this point I don’t care about what I was originally looking for (I’d forgotten anyway), I just want to see what the OMGoodness is going on in here and how C5 is using this stuff. I have no earthly idea where to find this integration information in the online docs, if it is even there (which I doubt), so I keep digging on my computer.

I take a wild guess, and go to concrete/vendor/illuminate/support/facades, and there I find a Facade.php file. I open it. My assumption is that this class is using a PHP magic method to infinitely overload names of things extended from Facade. And there we go:

__callStatic. Tracing the code, I see that getFacadeRoot() is diddling around to figure out the right class. At this point we’re getting deep into the Laravel framework components. So I need to hit the Interwebs. After some time of reading about the Laravel monster, and also about Symfony, and glancing at some other stuff involved, I go looking in the C5 code again. But still, I can’t for the life of me figure out exactly where the ‘url’ name referenced in that Facade derived class, URL, is getting registered with the frameworks, but I do find … some things. I started going in circles at that point trying to figure which thing was being registered with a service name like ‘url’ that has a to() method on it, or which thing with a to() method was being registered as the url service. There’s a promising class called Redirect in concrete/src/Routing/Redirect.php, but I’m not sure that’s getting me the class I’m after. Interestingly it also has a conditional in its to() method that in theory could lead to a call to a static function \URL::to, which — as we know at this point — I can’t find anywhere, except as that facade, maybe, but then …. well ….

… if this to() is what the URL::to() of my quest resolves to, then we could potentially have a bit of a problem here.

At this point, I just decided that short of hooking up a PHP debugger that would let me step through a program, I’d probably never figure out exactly what implementation of what was giving me a URL::to(). And I’m still not an inch closer to learning what those parameters for that action() method (remember that?) might be.

And that’s my point.

There’s nothing simple or elegant about the architecture. It’s counter-intuitive and extremely difficult to decipher. It’s dependent on at least Laravel and Symfony (whether just the Symfony components that Laravel packages up with itself or more, I don’t know), but there are also a lot more doodads down in its “vendor” directory. It looks like C5 is built using umpteen frameworks, libraries, etc., etc., in whole or in part (or maybe doesn’t use most of them at all, but chunks are still in there from some bygone day).

The docs are largely useless. You have to resort to reverse engineering code (involving large, complex 3rd party frameworks) and trial and error. I haven’t run across any architecture models or even lists of dependencies. And the forums are barely useful — not because people in the forums don’t know stuff, but the search of past posts ends up like the docs: one tells you to do things one way, the next tells you that’s deprecated, or a better way is another way, and sometimes they lead you through a chain of posts and documentation pages that takes you in circles.

Over all my impression of Concrete5 is: a tangled, convoluted, bloated, badly documented, nightmarish mess.

Categories
Uncategorized

Dynamic CSS

I was working with someone on coding some XSLT processing in WordPress earlier today, and for some reason it led me to think about something that had never really occurred to me before:

<link rel="stylesheet" href="mycss.php">

I know there are a bunch of tools out there for templating CSS and all that jazz, and I’ve used them, and I don’t really like them — they require more infrastructure to the dev environment for far less gain than they cost (in terms of packages to install, stuff to maintain, compatibility issues, headaches, etc.).

So, I did this little thing:

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <script>
      var thesize='IsLarge';
      var iw=window.innerWidth;
      if(window.matchMedia("(max-width:800px)").matches)
        thesize="IsSmall";
      var lel=document.createElement("link");
      lel.rel="stylesheet";
      lel.href="mycss.php?ts=" + thesize + "&iw=" + iw;
      var h=document.getElementsByTagName("head");
      h[0].appendChild(lel);
    </script>
  </head>
  <body>
    <div class="mystyle">
      This is the mystyle block.
    </div>
  </body>
</html>

And put this in mycss.php:

<?php
  header('Content-Type: text/css; charset=utf-8');
  $c='yellow';
  if($_GET['ts']=='IsLarge')
    $c='green';
  else if($_GET['ts']=='IsSmall')
    $c='red';
  $iw=$_GET['iw'];

  $boxw=(int)($iw) - 100;
  $boxw=(string)($boxw) . 'px';
  echo ".mystyle {background-color:$c;height:400px;width:$boxw;}";
?>

And that did exactly what hoped — sent the result of the client side media query as well a the innerWidth property value of the browser window to the server, and then I could use that information to conditionally produce the styling. A big value in that, I think, is that it allows the use of PHP variables and constants for dynamically generating things that don’t allow for CSS variables, e.g.,

@media screen and (max-width: 621px)

Which you could code as something like:

echo "@media screen and (max-width: $myCustomWidth)";

Even if you don’t like the idea of generating CSS on the fly (why not? load time? are you using a CMS like WordPress? Is one more small PHP script execution really going to matter?), the technique could be used for development, for adjusting things until you get it the way you want, then just hit the “mycss.php” (or whatever) file directly in your browser to emit the CSS to put in a style.css (or whatever) file. For instance, if I invoke my example with this:

http://localhost/dyncss/mycss.php?ts=IsLarge&iw=672

Then I get this returned to the browser:

.mystyle {background-color:green;height:400px;width:572px;}

If I’d written the PHP file to generate responsive CSS, then I may not even have needed the GET query args, though I’d probably use the iw one while developing to get it where I wanted. I could also write the GET args to a <div> or alert, or even invoke the mycss.php elsewhere in the same page with the same args and dump the response into a <div>, or log it to the console, to get that iw value exactly at the point I really liked the way the thing looked/behaved.

I’m just thinking out loud, and wondering to myself why this didn’t occur to me YEARS ago. *sigh*

Categories
Uncategorized

And So It Begins

I had no idea what I was doing. But in the end, I did it! I’ve put together a small business in the form of a limited liability company through which to operate my freelancing operations.

I also built a website for it and even wrote a nifty little Javascript/canvas animation that was really fun to construct: https://primalapparatus.com.

Categories
Uncategorized

KISS

Back in college, one of the most — maybe THE most — important thing I learned about programming was, “code for change.” That was back before OOP and stuff, when the mantra was rephrased as “design for change.” Or maybe I’m getting it all mixed up and I read “design for change” after college and never heard “code for change.” It doesn’t really matter, because I have a different point to make anyway.

I used to look at a software solution that was elegant and beautiful in its complexity and think that was Goodness. I used to write software like that. It worked well, lasted long, and was hell to pass on to “the next guy” to maintain. Then, one day, I set up a mini-lab in the office suite at work to run some experiments on a beautifully complex and elegant bit of software and discovered two things:

  • it was so complex that the developers seemed to have run out of time or money or both, and there were loose ends that they told me they thought were best, after all, left loose
  • it was doing several things the system it ran on would already do just fine without it.

Well, there was no way I was going to be digging around in all the complicated guts of that software (it is open source) to finish what was decided would be left undone. So, I went back to the drawing board and re-designed the solution without it, based on the realization expressed above in bullet #2. And what happened?

The resulting solution is elegant and beautiful in its simplicity, it works very well, and has lasted a long time. It will also be easy to pass on to “the next guy.” The overused expression “keep it simple stupid” is not really overused, it is merely under-observed. While complexity probably cannot be avoided in programs of any appreciable size, or richness of features, or ease of use, I think that remembering to “keep it simple as possible stupid” is apt.

And that brings me back around to designing for change. If you can keep in mind that someday someone (probably you) will have to change that code, you’ll opt for the simpler, more clear design. If you do the discovery and design phases well, then it should be a (in the world of IT) long time before that happens. So, when it does, you’ll thank yourself that you kept it simple for the distant day in the future that arrived and you were stupid. Stupid in the since that you completely forgot through the mists of the ages since you wrote it how it works. You have to re-discover what you once invented, probably under the gun of something “urgent,” and you’ll be thanking the past you who kept it simple and coded for change.

Categories
Uncategorized

Going Rogue!

I’ve been thinking about shifting to solely freelance programming/server administration work for several years, and due to several fortuitous factors, it seems the time is ripe to begin building a personal freelance IT services business. Until I have my portfolio and résumé online, please see the About page for a brief synopsis of my experience and skills.