PoP Blog

on 12 Jul, 16:49

New feature: automated emails

New feature: automated emails
Blog

Our latest implemented feature is a great one: all content in the website, either general content open to the public, as much as personal content that only logged in users can see, can also be sent through email, with no extra effort or duplicated work, because the email html code can be produced from the same source as the website pages. This is indeed code reusability to the extreme: creating a webpage can be used in both front and back-end (through server-side rendered html), and now also in emails sent to the users.

Even more, there is no need even to convert CSS to inline styles for the emails, since this is already taken care of automatically using library PHP CSS Parser (there is a limitation though: it only works for single-level classenames (eg: .btn); there is no support for other forms in the css, such as concatenated classnames (eg: .btn.btn-info), nested classes (such as .btn.btn-info), or html elements (eg: input[type="submit"]).

Digest with personal notifications, sent daily to the users

Digest with personal notifications, sent daily to the users

This way, it is now possible to create email digests with any content shown in the website, such as:

  • Personal daily notifications
  • Daily digests of new posts
  • Daily digests of upcoming events
  • Reminder emails to the users attending an event, on the day of the event (“Attend event” functionality must still be implemented #7)
  • Feedback emails to review the quality of the service sent to a user buying a product, after it has been delivered (the market place must still be implemented #14)
  • Others

All implemented new code can be found under wp-content/plugins/pop-frontendengine/library/css-to-style-conversion and wp-content/plugins/poptheme-wassup-automatedemails.

As always, enjoy!

on 2 Jul, 04:35

Explaining the coding principles guiding the development of PoP’s base code

Explaining the coding principles guiding the development of PoP’s base code
Blog

There are several coding principles guiding the development of all code in PoP:

1. Reuse and leverage

All code we produce must be reusable, as much as possible, all through out the application. In addition, we use existing 3rd party (open source) libraries to provide the functionalities we need, and integrate them to the framework. Since the PoP framework has been done, all from the beginning, by just one person, reusing code from both internal and external sources been of extreme importance.

 

WordPress code reuse

WordPress currently powers 28% of all websites in the world, and their community of developers is huge. It seems that, for every new technology out there, there will be a plug-in implementing it in no time. By using WordPress in the back-end as a service, PoP leverages the power of the WordPress community, integrating their plugins into the framework.

 

Isomorphic rendering

Isomorphism means that developers can implement the code only once and use it everywhere. Those single pieces of code are Handlebars javascript templates, from which PoP is able to create the HTML for:

  • front-end rendering, powering the Single-Page Application architecture
  • server-side rendering (SSR), producing HTML on the server for the initial website load
  • email digests and newsletters

 

Atomicity/Reusability of modules

A PoP module is either an atomic/reusable functionality, a composition of other modules, or a combination of the two. This way, modules can build upon each other, create complex layouts and structures from very tiny and simple components, as if playing with LEGO.

This scheme allows for implementing Separation of Concerns, in which a module tackles a specific problem and nothing else, and the collaboration among developers, in which several developers can be working alongside each other on the same module, without conflict.

 

Microservices

PoP’s decentralized architecture enables to create applications which get their data from different smaller websites, emulating microservices. This way, content that needs to be repeated in several websites can be extracted into an external entity and feed its data to everyone who needs it.

For instance, if you have 3 websites with ads, and all 3 need to show the same ad, instead of creating the same post with that ad image in all 3 websites, it is possible to create a 4th website, placed under ads.mydomain.com, create the ad just there, just once, and inject its data (in this case, the ad) into all 3 other websites.

 

2. Decouple

All code in PoP is decoupled as much as possible. We try to not depend on any specific software solution or vendor, and the implementation of the base code decouples the business logic, the presentation, accessing the database, and the configuration into different layers, which do not overlap into each other.

In addition, modules are composed in a top-down manner, and configured through dependency-injection, so that a developer overseeing the construction of the application at the top can change the behaviour of the different components, which are being built, at the same time, by other developers.

 

No dependency on WordPress (in theory)

Even though PoP currently is based on WordPress, this dependency was built loosely in the architecture, so that a different software system could replace WordPress if needed. Because PoP is built using PHP, other CMS solutions also based on PHP, such as Joomla or Drupal, could be plugged in without much trouble (this is in theory; in practice, there is still plenty of work to do to achieve an absolute decoupling, but the overall architecture has already been designed in this fashion and for this purpose).

 

Decoupling of business/presentation/database/configuration layers

All following elements are decoupled one from each other, and as such can be developed, concurrently, by different developers with different skills:

  • View design (through Handlebars javascript templates) and configuration (through PHP objects)
  • Javascript functions
  • Styles
  • Access to the database

 

Dependency injection

All modules can declare what properties can be configured, and allow their parent modules to modify this configuration in a top-down manner, in which upper modules take precedence over lower modules. This way, a developer overseeing the construction of the application can modify the behaviour of the application accordingly, and needs not bother the team building the components. This scheme effectively adds a layer of decoupling even among the development team.

 

3. Cache

PoP makes heavy use of caching, wherever possible. It implements several layers of caching:

 

Server cache (through WP Super Cache)

This is the standard cache: whenever a URL is requested, it caches the produced HTML in the server, so that the next request to the same URL needs not generate the response again.

 

Configuration cache

Because the configuration is decoupled from everything else, such as the object data, then it can be cached. Differently from the server cache, the configuration cache does not rely on the URL, but on the type of page that is requested, which can be applied more often.

For instance, if two event pages are requested, even though they have different object data (i.e. their title, content, date, etc), their configuration (i.e. the classnames, color, fonts, etc) will still be the same. Then, requesting the first event will generate the page as usual, but requesting the second one will only need to get the data from the database and nothing else, since the configuration can be reused after it was generated and cached for the first event. This way, the second request will be processed faster.

 

Content CDN + Asset CDN

A CDN is a network of servers which is located near the user, so requesting resources from it is generally faster than requesting them from the server. All static assets from the application (such as images, .js and .css files, PDFs, etc) can be normally cached in CDN, and PoP is no exception. However there is nothing extraordinary here.

There is magic, though, concerning the Content CDN: dynamic content, such as a post data, can also be cached in a CDN on its way back to the server. PoP indeed makes the best from both worlds: dynamic content generated in a CMS, such as WordPress, which behaves as if coming from a static site generator.

 

Service Workers

Finally, PoP implements the offline first strategy for caching all accessed content in a browser cache, so that it can be retrieved faster, and even when the user is offline. Through the use of the Cache then network strategy, PoP will serve content in no time, directly from the browser cache, but still notify the user if/when there is more up-to-date content.

on 15 Jun, 09:17

Javascript implementations of WordPress features in PoP

Javascript implementations of WordPress features in PoP
Blog

Recently there has been a discussion among the WordPress development community on what javascript framework should be chosen to be added to WordPress in the near future, with React and Vue as the most likely candidates. In that same blog post, a comment was highlighting that the discussion is not focusing on how good each framework is at implementing those functionalities which sit at the very core of WordPress, such as: hooking, localization and dynamic activation/deactivation of modules.

Concepts alike to these functionalities have been implemented for the PoP javascript engine. In this blog post we will detail how our solutions have been designed and implemented.

Dynamic activation/deactivation of modules

An object called JSLibraryManager allows to register javascript function through objects. This object has function register, where JS objects can register themselves for each function they are implementing, and function execute which triggers the execution of the specified function in all objects which registered themselves as implementing it.

(function($){
JSLibraryManager = {

  // All the registered JS libraries
  libraries: [],

  // All the methods that each library can handle. Each method can be served by different libraries
  // This way each library can also serve common methods, like 'destroy', 'getState', 'clearState', etc
  methods: {},

  register : function(library, methods, highPriority, override) {

    var t = this;

    t.libraries.push(library);
    $.each(methods, function(index, method) {

      // override: allows for any library to override others
      if (!t.methods[method] || override) {
        t.methods[method] = [];
      }

      if (highPriority) {
        t.methods[method].unshift(library);
      }
      else {
        t.methods[method].push(library);
      }
    })
  },

  execute : function(method, args) {

    var t = this;

    var ret = {};
    var libraries = t.methods[method];
    if (libraries) {
      $.each(libraries, function(index, library) {

        ret['l'+index] = library[method](args);
      });
    }

    return ret;
  }
};
})(jQuery);

A javascript object then registers all its public functions under JSLibraryManager:

(function($){
popBootstrap = {

  tooltip : function(args) {
    
    var t = this;
    var pageSection = args.pageSection, targets = args.targets;

    jQuery(document).ready( function($) {
      
      targets.each(function() {

        var tooltip = $(this);
        var options = {
          placement : tooltip.data('tooltip-placement') || "top",
          title: tooltip.attr('title'),
        };

        tooltip.tooltip(options);
      });    
    });    
  },

  popover : function(args) {

    var t = this;
    var pageSection = args.pageSection, block = args.block, targets = args.targets;
    jQuery(document).ready( function($) {
      
      var options = {
        placement: 'auto',
        delay: {
          hide: 100
        },
      };    
      targets.each(function() {

        var popover = $(this);
        var popoverTarget = $(popover.data('popover-target')).first();
        var content = popoverTarget.html();
        var popoverOptions = $.extend({}, options, {content: content});
        popover.popover(popoverOptions)
      });  
    });  
  },  
};
})(jQuery);

//-------------------------------------------------
// Register all functions
//-------------------------------------------------
JSLibraryManager.register(popBootstrap, ['tooltip', 'popover']);

Finally, in the PHP object we specify what javascript functions must be executed on the newly created elements on the DOM, for each module:

class PoP_Template_Processor_PopoverLayoutsBase extends GD_Template_ProcessorBase {

  ...

  function get_block_jsmethod($template_id, $atts) {

    $ret = parent::get_block_jsmethod($template_id, $atts);  
    $this->add_jsmethod($ret, 'popover');    
    return $ret;
  }
}

The PoP engine in the frontend will execute the specified javascript functions for each module, by calling the method execute from  JSLibraryManager, which will invoke all registered functions under that name. If no javascript object has registered as implementing it, then nothing will happen.

When activating a WordPress plugin, it will load its .js files containing javascript objects registering themselves; when deactivating, the .js files will never be loaded, and so its javascript objects will never be registered. Hence, activating/deactivating plugins will indeed do the same at the frontend side.

Hooking

Adding actions and filters to javascript is a continuation of the strategy defined above. We can define any hook as a function, to be invoked under some name, under which can register those javascript objects implementing the hook.

Let’s see an example. Say that we need to modify some value, but we don’t know or care about who will modify it, we can simply call function execute from JSLibraryManager, passing the name of the hook and an object containing all values to modify alongside other needed values. Because javascript passes objects by reference, the modified properties of the object can be read again after the completion of the execution.

function fetchURL(url, target) {
  
  ...

  // Allow plug-ins to modify the url
  var args = {
    url: url,
    target: target
  };
  JSLibraryManager.execute('hookFetchURL', args);
  url = args.url;

  fetch(url);
}

Finally, we register the functions implementing the hooks, by registering an object and its functions under JSLibraryManager.

(function($){
HookObject = {

  hookFetchURL : function(args) {
  
    var t = this;
    args.url = t.add_query_arg(args.url, 'timestamp', Date.now());
  },

  add_query_arg : function(key, value, url) {

    url += (url.split('?')[1] ? '&':'?') + key + '=' + value;
    return url;
  }
};
})(jQuery);

//-------------------------------------------------
// Register all functions
//-------------------------------------------------
JSLibraryManager.register(HookObject, ['hookFetchURL']);

Localization

PoP does not attempt to provide localization features in the front-end. Instead, all values are already localized from the back-end, and sent as configuration values in the JSON code provided by the API.

In other words, we do not create a javascript template with this logic:

Your event is on {{localize "13/08/2017"}}

Instead, our Handlebars javascript template is like this:

{{titles.event-date}}

And then we generate the values on the back-end as it is usually done with WordPress, filling it in the configuration of a module, done in its corresponding PHP object:

class PoP_Template_Processor_EventLayoutsBase extends GD_Template_ProcessorBase {

  function get_template_configuration($template_id, $atts) {
  
    $ret = parent::get_template_configuration($template_id, $atts);

    $ret['titles'] = array(
      'event-date' => sprintf(
        __('Your event is on %s'),
        date_i18n(get_option('date_format'), strtotime('13-08-2017'))
      )
    );

    return $ret;
  }
  ...
}

Finally, the PoP engine in the front-end will merge the configuration with the javascript template, and produce the desired output.

on 15 Jun, 00:38

New feature: Isomorphic rendering—server-side html produced using javascript templates

New feature: Isomorphic rendering—server-side html produced using javascript templates
Blog

PoP now provides isomorphic rendering capabilities: it allows to render HTML both in the server-side and in the front-end, and the code used for both is the same: precompiled Handlebars javascript templates, rendered in the front-end using the Handlebars runtime library, and in the back-end using LightnCandy.

This feature allows to render HTML straight from the server when first loading the website, which produces a very quick initial response, yet render all HTML code in the frontend through javascript, in a Single-Page Application fashion, from the 2nd page-load onwards.

What are the advantages of isomorphism?

There are quite a few, such as:

SEO: all search engines can parse the site’s HTML (Google can parse websites built with Javascript, but others, such as Bing, still can’t).

Integration with technologies and systems: server-side HTML rendering is needed for implementing new technologies such as AMP and microformats, and for broad system interoperability.

Speed: the first page is loaded much faster, since it doesn’t need to wait to load javascript templates to render it. Starting on the 2nd page onwards, javascript takes over, rendering faster and making the website dynamic.

Re-usability: developers implement the code only once and use it everywhere: not just for producing HTML in the front and back-end, but even for generating transactional emails, embeddable widgets, and others.

Is it 100% fully isomorphic?

Ok, you got me. The amount of code that is reusable is around 95%, which corresponds to all the views produced using Handlebars templates. The remaining 5% corresponds to Handlebars helpers, that is javascript functions executed when producing the HTML code.

Javascript helper functions must be coded also in PHP for generating the HTML in the server-side, using LightnCandy. However, the syntaxes of javascript and PHP are so similar that this is such a trivial matter. Check out the following example:

Javascript helper function withModule:

Handlebars.registerHelper('withModule', function(context, module, options) {

	if (typeof context == 'undefined' || typeof context[M.JS_SETTINGSIDS] == 'undefined' || typeof context[M.JS_SETTINGSIDS][module] == 'undefined') {

		return;
	}

	// Get the module settings id from the configuration
	var moduleSettingsId = context[M.JS_SETTINGSIDS][module];//context['settings-ids'][module];

	if (typeof context[M.JS_MODULES] == 'undefined' || typeof context[M.JS_MODULES][moduleSettingsId] == 'undefined') {

		return;
	}

	// Go down to the module
	context = context[M.JS_MODULES][moduleSettingsId];

	// Expand the JS Keys
	popManager.expandJSKeys(context);

	// Read all hash options, and add them to the Context
	jQuery.extend(context, options.hash);

	return options.fn(context);
});

PHP helper function withModule:

function withModule($context, $module, $options) { 

	if (!$context || !isset($context[GD_JS_SETTINGSIDS]) || !isset($context[GD_JS_SETTINGSIDS][$module])) {

		return;
	}

	// Get the module settings id from the configuration
	$moduleSettingsId = $context[GD_JS_SETTINGSIDS][$module];

	if (!isset($context[GD_JS_MODULES]) || !isset($context[GD_JS_MODULES][$moduleSettingsId])) {

		return;
	}

	// Go down to the module
	$context = $context[GD_JS_MODULES][$moduleSettingsId];

	// Expand the JS Keys
	$popManager = PoP_ServerSide_Libraries_Factory::get_popmanager_instance();
	$popManager->expandJSKeys($context);

	// Read all hash options, and add them to the Context
	$context = array_merge(
		$context,
		$options['hash'] ?? array()
	);

	return $options['fn']($context);
}

From this function, it can be observed that migrating a function from Javascript to PHP involves a series of simple, well-defined steps:

  • Add $ to all variable names
  • type array[key] == 'undefined' => isset(array[key])
  • Use global $variable (or, in this case, access an instance through a Factory) to access some globally defined object, such as popManager in the javascript function.
  • Access functions using -> instead of .
  • jQuery.extend() => array_merge()

And voilà, in under 2 minutes, rather effortlessly, the function is ported from Javascript to PHP.

What comes next?

Having isomorphic rendering capabilities enables us to implement the following features in PoP:

  • Issue #53: AMP — Accelerated Mobile Pages Project
  • Issue #51: Microformats to integrate with the IndieWeb
  • Issue #46: Email digests
  • Issue #1: Create standalone PoP plug-ins, to provide functionalities from PoP to install on any WordPress website

As always, enjoy!

on 14 Jun, 00:12

PoP Tour Buenos Aires

PoP Tour Buenos Aires
Blog

Leo will be presenting PoP in several venues during June 2017:

  • The building blocks of Progressive Web Apps: Monday 19th in AreaTres
  • How to make a decentralized WordPress website using PoP:
    • Thursday 22nd in Belatrix, and
    • Friday 30th 7.30 pm in the Unversidad Abierta Interamericana, Av. San Juan 951 (no link yet)
Leo presenting PoP in Madrid

Leo presenting PoP in Madrid

We are also waiting for a few more presentations to be confirmed… we will keep this post updated

If you are around, we hope to see you there… Ciao!

on 12 Apr, 09:44

PoP has been accepted to Station F’s Founders Program!

PoP has been accepted to Station F’s Founders Program!
Blog

We are very proud to announce that PoP has been accepted in Station F, the biggest startup campus in the world, opening this July in Paris. We have been chosen for their Founders Program, together with around 100 startups from all over the world. With its never-ending 34,000 sq meters (similar size to the Eiffel Tower laying down!), 3000 desks for startups, and over 1,000 startups on campus, including companies such as Facebook and Zendesk, Station F is posed to dramatically alter the entrepreneurial scene not just for Paris, but also for much of the world.

And PoP will be there too!

stationf

We are moving in on July 7th, which is the day Station F opens its doors to startups, and staying for who-knows-how-long (we have booked at least 3 months for the time being). We will be delighted to meet entrepreneurs from all continents, and establish meaningful partnerships and collaborations.

And more importantly, we will be launching a new project to celebrate moving to our new home… Something far bigger and more ambitious than anything we have ever done… More details coming soon…

Welcome to the PoP framework!
Break the information monopoly

the PoP framework is open source software which aims to decentralize the content flow and break the information monopoly from large internet corporations. Read more.


Sign up to our newsletter: