“Why did I not think of this?” moment in MODX 3 snippet development with PHPStorm

This is one of those ‘Aha!’ moments.

MODX is one of CMSs (content management system) that I have been using for a long time to maintain my shogi site. Market penetration of this CMS is said to be 0.1%. As of this writing, 43% of of Web sites uses WordPress and no other CMS reach even 10% of market share. (source, w3techs.com . I actually think MODX penetration is much greater than this number, MODX does not leave big footprint to show it’s identity in front of web crawlers. -Many sites I know powered by MODX, including mine – were identified as non-CMS site by w3tech’s tool.— Nevertheless, there is no doubt WordPress dominates the CMS market)

Although both uses same language (PHP) for powering the site, MODX gives much more flexibility in site design but you need to be proficient with HTML and CSS (and JavaScript). In another word, MODX is a tool while WordPress is a product.

What I liked about MODX over WordPress at the time was a separation of PHP code and HTML. This was a long time ago so the situation might have changed on WordPress, but I have been happy with MODX since.

At the time, I also looked at Drupal and Joomra . All of them forces you to follow their interpretation of what website should be. MODX has no opinion on how you want to create Web site. You have a total freedom.

On the other hand, if the only thing you want to do with your site is blogging, there is no better solution than using WordPress.

I digressed. Back to the subject!

With a wealth of plug-ins available, your rarely need to code in PHP. When you do though, MODX separates a PHP coding part from HTML with a thing called Snippets. A snippet is then inserted in to HTML with a use of tag.

[[aSnippet]]

You can edit a snippet within MODX backend’s editor. With a plugin like ‘ACE’ there is a nominal amount of syntax checking to the PHP code. Unfortunately, I am being spoiled with convenience of IDE such as PHPStorm,

MODX backend, Snippet editor with ACE plugin

So there is a desire to be able to write a snippet code using PHPStorm and get benefits of auto-completion and methods hinting, strict error checking and warning.

Unfortunately, there is no plugin in PHPStorm for MODX or MODX plugn for PHPStorm.

When I google “MODX with PHPStorm”, there are several hits, Although none of them gave me a direct answer on what I wanted to do, I was able to put enough facts together and came up with a solution. The solution that was just waiting for me to assemble few known facts, that I have used all of them separately in the past!


1. Fact that PHPstorm can create a project using existing remote site contents, so that PHPStorm can pull all file setup from MODX site.

PHPStorm->File->New Project from Existing Files


2. Fact that PHPstorm can then start syncing file contents of my local project files to server files.

File sync options available in PHPStorm

Ok, but Snippet is stored in Database. the code is not in the file, but then,

3. Fact, MODX snippet code can be from a static file, meaning I can create a PHP file and feed it as a snippet to MODX by turning on “is Static” option and point to the file location

Is Static option is turned on for Snippet. Snippet is now fed from “static file”



Result: When I combine those 3 factors, I can create a snippet with a comfort of PHPStorm IDE environment.

Snippet now editable in PHPStorm
Snippet output on browser page, powered through MODX

What do I gain? Full context support and code hinting, as PHPStorm analyzes whole MODX site and figures out all variables and object and its methods being used inside MODX. I have to give credit to MODX development team for fully documenting source files. Thank you!

PHPstorm explains what getOption method is
PHPStorm autocomplete support in action.

You can also open the corresponding file by pointing to method and do control-b to drill down on function.

I edit a file in PHPStorm, and you either 1) turn on auto-sync between your local files and server files or 2) manually upload changed file to server. Then I can run and test the snippet with MODX backend immediately.

So all of the sudden, I feel like invincible. It will be very hard for me to make coding error. (Ok, logic error still possible)

Once Snippet development is done, you may switch off the ‘is static’ option and keep the snippet inside database, remove the php file from the system.

One thing that is kind of annoying is that by default, PHPstorm thinks $modx variable is undefined. The default setting on PHPStorm’s inspections on undefined variable is somewhat on conservative side. It will not even acknowledge variables from included file!. To mitigate this, you need to put a check on “Search for variable’s definition outside the current file”

PHP settings->Editor->Inspection->PHP->Undefined symbols->Undefined variable

It hurts to think that I have been using both PHPstorm and MODX for more than 10 years and I am figuring this out just now 🙁

Creating a Blog page inside MODX version 3 web site

MODX comes clean slate so there is no ‘ready to use’ provisions for creating Blog style site. One has to set it up using tools available in the CMS.

I took an easy way out for my production site by creating blog site using free wordPress service and then feed content to MODX page. with this, the only extra you will need is Spiefeed to handle rss feed from WordPress.  But for purist approach it is certainly possible to setup blog section within MODX using few extras.

There are several articles available for creating Blog sites using MODX.  The one shown in the modx official site is somewhat dated, but the article actually have a link to the instruction/article of more recent implementation of MODX blog site.  Link is here.   Better yet, this instruction is accompanied with a package published in the github which has all chunks, a snippet and a template packaged up to duplicate the blog site that the article discusses.  A demo site is also available to check out the feel of using this template. The document states that the demo utilizes MODX 2.7.  So can I use this setup with MODX 3 site? Furthermore, the instruction assumes you want the Site to be a blogging site. Can I add ‘Blog page’ to already existing MODX site? Answer to both questions are ‘Yes’ but we need to modify some parts.

To start, I could have created each chunk and template manually following the instruction but to reduce my typing effort, I went ahead and downloaded the demo package. I also installed dependent extras (getResources, getPage, Collections, and Tagger).  Previously, I did not have any of those installed. – I am using pdoTools  to get resources and get page. – <edit> It was fairly easy to change references to getResources and getPage to equivalent pdo* snippets.

Again, the setup instruction is written for MODX version 2.7 and the site I am setting up this blog structure is version 3.0.3.  Setup also assumes the top page is a site home page. There are several area in chunks and template that refers to [[++site_start]] and this need to be changed to point to correct Resource.  I want to have a blog page as a subpage of the site.

Looking through the template and snippets that I setup with the downloaded package , I found some more modifications were needed.

I will list out those changes.

  1. My server uses Nginx and it needs additional html tag to specify base url in <head> section of blog template html. Without it, Friendly URL won’t work correctly.
    <base href="[[++site_url]]">
  2. In MODX 3, [[*class_key]] does not return “modResource”.  It returns “MODX\Revolution\modResource”.
    This means I get “MODX/Revolution\modDocument” or “MODX\Revolution\CollectionContainer” in [[*class_key]] field depending on resource selected. Two sections of “Blog Template” stops working due to this.

    1. Template tries to pull in “jumbotron_CollectionContainer” or “jumbotron chunk based on [[$jumbotron-[[]*class_key]]] tag. This tag doesn’t work in MODX 3 as it returns [[$jumbotron-MODX/Revolution/….]] which does not exist and forward slash within chunk name is probably invalid anyway.
    2. Template tries to insert [[$blog_listing]] or [[$blog_article]] based on conditional modifier [[*id:is`[[++site_start]]`:then….]] but the blog_listing page is not at [[+site_start]] resources in my use case.
      1. To mitigate both problems, I have created a system setting [[++blog_start]] in custom namespace/area and set it to id of a blog home page resource I created. Then rewrote tags as follows.
        For jumbotron section
        [[[[*id:is=`[[++blog_start]]`:then=`$jumbotron-CollectionContainer`:else`$jumbotron-modDocument`]]]]
        For container section
        [[[[*id:is=`[[++blog_start]]`:then=`$blog_listing`:else=`$blog_article`]]]]
      2. Note: It will be probably not that difficult to create snippets and replace conditional tags here.
  3. getResources and getSnippet tags are used to aggregate child resources and parents properties are set to site home page [[++site_start]].   These needed to be changed to aforementioned [[++blog_start]].  These changes had to be made on $blog_listing chunk and $jumbotron-CollectionContainer chunk.
  4. @groups properties are hardcoded in calls to TaggerGetTags snippet.  The snippet is called from $aside chunk is setting @groups to 1 and the snippet called from $headder chunk is setting @groups to 2.  Make sure this agrees with your tagger group settings. I have first created ‘Category’ group and then ‘Archives’ group so I needed to change them to 2 and 1 respectively.
  5. Last and least 🙂   as this is just a demo template, links to “subscribe”, “search”, “Sign up”, “GitHub”, “Twitter” and “Facebook” are all mocked and pointing to itself.  You either need to remove or put actual link to them when modifying to suit your site design.

So, in order to create a Blog section within Modx 3 hosted website, using this instruction and elements in the github repo, One needs to be aware of:

  1. Modx version 3’s breaking change of the model class caused decision logics inside Blog_Template to stop working.  Rework of the logic flow was needed.
  2. Friendly url.  Nginx needs base href reference in head section.
  3. Creating a blog section other than home page location. Needed to change references to [[++site_start]] system settings to [[++blog_start]], a user created system setting
  4. Adjust the template design to fit with other area of site design.

Some more miscellaneous items to note.

  1. $blog_listing_item chunk, content placeholder has a modifier :firstp. There is a firstp snippet that is installed with the package.  I opted to replace it with ellipsis=`500` modifier to limit the content output to first 500 chars followed by ellipsis to suit my preference.
  2. Also in $blog_listing, getPage snippet uses @blog properties set. This set does not exists so the default property set will be used instead. I think idea is to create a blog property set within getPage snippet to override the default property settings in easy way, if customization is needed.

Commenting on the posts are not possible.  This need to be setup by yourself and will require Quip extra. that part is not covered by this article. One has to go back to modx documentation’s tutorial section.

 

factory function?

JavaScriptやPHPで、Function Factoryという言葉を見るのだが、これは共通するパターンのFunctionを生成するためのFunctionということで、例えば

$double = function($x){
    return $x*2;
};

$triple = function($x){
    return $x*3;
};

$quadruple = function($x){
     return $x*4;
};

なんてのは、三つのfunctionを定義していても、よく見ると、2,3,4とかける数字が違うだけで、あとはまったく同じパターン。 このようなfunctionの記述を効率よく行うために

// This is function factory
$create_multiplier = function($y){
    return function($x) use ($y) {
        return $x * $y;
    };
};
//use the function factory to create three functions.
$double = $create_multiplier(2);
$triple = $create_multiplier(3);
$quadruple = $create_multiplier(4);

というような書き方をするテクニック。肝心な部分の記述は一回で済むためコードの管理も簡単になる。

上のコードは返すコードのなかで、$xを認識させるため、 use ( $x )というクローズをいれているが、PHP7.4 からPHPでもアローファンクションが使えるようになり、これだとuse というkeyword無しで、外側で設定されている変数を認識するようになる。ので、

$create_multiplier = function($y){ return fn($x)=>$x*$y;};

//use function factory to create three functions.

$double = $create_multiplier(2);
$triple = $create_multiplier(3);
$quadruple = $create_multiplier(4);

と、ファクトリーの部分の記述がすっきりする。

さらにこの上位のファンクションもアローファンクションで書いてしまうと

$create_multiplier = fn($y)=>fn($x)=>$x*$y;

となり、 プロのコーディングでアローが二つも三つもかさなるような記述が時々でてくるのだが、そろそろ読解がしんどくなってくるので、後で読み返してわかる記述方法としては、よし悪しかなあ。