platformOS

Platform OS Blog Module

Adam Broadway | July 23, 2018

Websites live (and die) by the ability to be found by Search Engines.


And critically, content - high quality, knowledge sharing content - is a key point ensuring your blog is found, read, and shared.


Many blog engines built over the last decade have not kept up with the pace of technological and search engine algorithm change.

To get around that, developers create 3rd party plugins for monolithic Blog engines, that can become bloated, slow, and extremely difficult to maintain.  (Ever tried to update 5+ plugins after a blog engine security upgrade was made, and now it’s broken or worse yet, those SEO optimizing plugins don’t work any more?)

A new breed of Blogging services needs to also think about future proofing not only content writing and publishing for an SEO optimized web page, but also for easy syndication and access to the content via API’s.
A flexible, API-centric blogging engine will allow specific Blog content to also be easily accessible by native Mobile apps, Internet of Things devices, billboards, TV, electronic paper, or translation and reading devices.


So we took a step back when developing the Platform OS Blog engine to ensure the key points above were future-proofed.  

Platform OS is the all-in-one software platform for creating powerful online businesses, marketplace communities, and applications that connect buyers and sellers, guests and hosts, experts and clients, and helps to build nurturing Communities of Practice and Communities of Interest.

It includes a User Blog or “Micro Blog” option, to allow for User Generated Content to be created, moderated and published.

With an “APIs for everything” approach powered by leading technologies like GraphQL, Liquid, YAML, Elasticsearch, and a wide range of integrations, Platform OS provides a flexible platform for building any kind of site big or small—from landing pages to community marketplaces.


We are planning a series of articles that provide some insight into the thinking behind different components of Platform OS. In this article we discuss the architecture and main features of our Blog Module.

Blog Module architecture

Blog is built entirely on Customizations, meaning its architecture can be easily modified. Not only is it possible to alter core module features—it’s very simple to add new ones.

Core Custom Model Types

After installation, you can see the list of files added to the project. There are two Custom Model Types at the core of the Blog Module:

  • Blog Instance: used to save all blog settings

  • Blog Post: stores information about all blog posts


By editing the generated configuration files, you can easily alter or add to Attributes of Custom Models.


name: Blog Instance
custom_attributes:
- name: title
  attribute_type: string
- name: subtitle
  attribute_type: string
- name: scope
  attribute_type: string
- name: slug
  attribute_type: string
- name: facebook_app_id
  attribute_type: string
- name: enabled
  attribute_type: boolean
- name: sidebar_enabled
  attribute_type: boolean
- name: grid_view_enabled
  attribute_type: boolean
- name: tags_filter
  attribute_type: array
- name: header_logo
  attribute_type: photo
- name: header_icon
  attribute_type: photo
- name: header_image
  attribute_type: photo
  versions_configuration:
    normal:
      width: 740
      height: 300

custom_model_types/blog_instance.yml

Settings and posts

Blog settings and posts are fetched with GraphQL queries. The flexibility of GraphQL gives possibility to implement any search functionality we need. Every custom attribute added to the configuration will be available to add to the installed queries:


query get_blog_posts(
  $per_page: Int,
  $page: Int,
  $title: String,
  $id: ID,
  $slug: String,
  $published_at_lte: String,
  $published_at_lt: String,
  $published_at_gt: String,
  $published_at_gte: String,
  $tags: [String],
  $blog_instance_id: String,
)
{
    customizations (
    is_deleted: false
        per_page: $per_page
        page: $page
        id: $id
        name: "blog_post"
    sort: [
      {
        name: "properties.published_at"
        order: "desc"
      }
    ]
        properties: [
            {
                name: "tags"
                values: $tags
        values_operator: OR
            },
            {
                name: "blog_instance_id"
                value: $blog_instance_id
            },
            {
                name: "title"
                value: $title
            }
            {
                name: "slug"
                value: $slug
            }
            {
                name: "published_at"
                range: {
          lte: $published_at_lte
        }
            }
            {
                name: "published_at"
                range: {
          lt: $published_at_lt
        }
            }
            {
                name: "published_at"
                range: {
          gt: $published_at_gt
        }
            }
            {
                name: "published_at"
                range: {
          gte: $published_at_gte
        }
            }
        ]
    )
  {
    current_page
    per_page
        total_entries
        total_pages
        has_next_page
        has_previous_page
        results {
      id
      user {
        id
      }
      created_at
      author_name: property(name: "author_name")
      blog_instance_id: property(name: "blog_instance_id")
      author_biography: property(name: "author_biography")
      content: property(name: "content")
      excerpt: property(name: "excerpt")
      published_at: property(name: "published_at")
      title: property(name: "title")
      slug: property(name: "slug")
      tags: property_array(name: "tags")
      hero_image: custom_image(name: "hero_image") {
        normal: url(version: "normal")
        thumb: url(version: "thumb")
        transformed: url(version: "transformed")
      }
      author_avatar: custom_image(name: "author_avatar") {
        thumb: url(version: "thumb")
      }
        }
    }
}

graph_queries/get_blog_posts.graphql sample

Data representation

Data presentation is handled by pages and partials included in proper layouts. Administrative part of Blog Module is guarded with predefined Authorization Policies. Permissions differ based on the type of the blog installed:

---
name: instance_blog_edition
redirect_to: '/blog'
flash_alert: 'Please log in to access this page.'
---
{% query_graph "get_blog_user", result_name: g %}
{% if g.current_user and g.current_user.admin_profile %}true{% endif %}

authorization_policies/instance_blog_edition.liquid


The Blog Module installs the “admin” user profile by default. If you wish to use another user profile as your administrator user group, please adjust the above file and the get_blog_user GraqhQL query.

Blog Module features

The architecture of the Blog Module (and Platform OS in general) allows for incredible flexibility regarding built-in and extended features. Besides the basic functionality of setting up and managing a blog, you can implement user blogs with fully customizable admin and interface themes. Let’s delve into some features of our Blog Module, and learn more about how we’ve implemented them and how you can use them.

User blogs

In the case where you might be building a Community site, a Marketplace or Membership Management Portal, you might like to allow users or contacts in your community to also Blog.

Platform OS has a “User Blog” feature, to empower users who are granted the right permissions, to also create and manage their own ‘micro blog’. From a technical point of view, user blogs can have the same features as the main blog. The only difference is in privileges:

  • In case of the main blog (called Instance blog in Platform OS), the Instance owner can create and edit posts.

  • User blogs allow any user to create a blog, and the owner of the blog can create and edit posts.

SEO compatibility

Friendly URLs

You can create your own URL template that is compatible with the URI Template standard.

To access parameters passed in the URL in Liquid markup, use the extract_url_params Liquid filter.

{% assign example_url = "/cars/honda/crx" %}

{% assign url_template = '/cars/{maker}/{model}' %}
{% assign url_params = example_url | extract_url_params: url_template %}

{{ url_params }} => {"maker"=>"honda", "model"=>"crx"}
{{ url_params.maker }} => "honda"
{{ url_params | json }} => {"maker":"honda","model":"crx"}

Having the parameters from the request URL, you can retrieve data based on those parameters.


For example you can write a query that will take these parameters and:

  1. return only posts from category “honda” and

  2. posts that have tag “crx” and

  3. published in the last 3 months and

  4. are marked as “published” (as opposed to draft) and

  5. sort them by publish date


In GraphQL you have full control over your search results, so besides filtering posts that you are interested in, you can decide exactly what kind of data the query will return. For example, you might be interested only in the slugs and publish date of posts to create a “Related posts” box—easy to do with GraphQL.

Performance

Platform OS places your assets on one of the best content delivery networks, CloudFront. This ensures that your users (and search engines) will load the assets as quickly as possible regardless of their geographic location. Our servers will handle caching by default, but if you want to change it, you can.


You have full control over HTML sent to the browser. This means you will not have any resources loaded by Platform OS itself. Think of a clean slate that you fill, without being forced to load anything.

SSL out of the box

All marketplaces are equipped with SSL certificates by default and you can easily switch it to your own if needed.

Landing pages

As described, you have full access to your data via GraphQL, and you can parameterize your GraphQL queries using parameters extracted from the URL. Creating dynamic landing pages that pull data from the database based on the URL allows you to make your content easily accessible for users.


Some of the most commonly used features:


  • Blog posts content: show previous/next blog posts in the same category

  • Top X: show the most popular blog posts (e.g. most liked, commented)

  • Featured: highlight a post based on your defined criteria

  • Related: group and crossmatch groups of posts to make them discoverable to users accessing one of them from one of the landing pages based on metadata that you create.
    For example: If a user comes from the category “SEO”, you might want to show related posts from the SEO category, but also from the first three tags from this post. This provides powerful flexibility in making sets of content that are interconnected, and allows you to promote your most valuable content.

Full control

Liquid markup gives creators full access to the HTML that will be rendered. Because it’s a template engine, and you have access to the database on that level, you can easily control your meta tags.


Having full control over your HTML output is also a big advantage when it comes to promoting your content on social media. Google provides excellent documentation on taking full advantage of OpenGraph attributes to create rich media snippets when sharing links to your pages—read more about Social Discovery on Google.

Google AMP compatibility

Because an AMP page is just an HTML page inside a required boilerplate and compliant with AMP rules, you can freely develop an AMP site using Platform OS. You can even get any free template from https://www.ampstart.com/getstarted and place it directly into your assets directory, and it will be live immediately. In a couple of minutes you can extract the layout part to a layout, and the content of the pages to Liquid pages. That way your code will be DRY and your life easier should you want to change anything on all pages (e.g. footer, tracking code, navigation).


That said, you still have access to the power of Liquid, GraphQL and the whole backend behind Platform OS, even if you keep your code lean to comply with AMP restrictions.


See some AMP compatible example sites here:
https://amp-demo-ecommerce.oregon.near-me.com/

https://amp-demo-travel.oregon.near-me.com/

https://amp-demo-lune.oregon.near-me.com/

https://amp-demo-gallery.oregon.near-me.com/gallery

https://amp-demo-blog.oregon.near-me.com/

Analytics

In-browser analytics

Having control over all parts of your entity gives you the ability to use any analytics tool that you can think of.


Using Google Analytics is as easy as copying and pasting their HTML snippet into your layout.


Sending additional information about authenticated users of the system is as easy as pulling the data using GraphQL or using the global `context` object and pasting it into the object sent to Google servers.


Custom analytics

Because you can save any data into the database and pull it from GraphQL, you can create custom reports/analytics based on your criteria. You have access to the aggregation engine provided by ElasticSearch on the backend, so it’s blazingly fast. After pulling the data it’s up to you to decide how you want it to be presented. You may want to expose it as a JSON endpoint, render an SVG image with a chart, or do a hybrid—expose JSON endpoint and use it in your favorite charting library.


Analytics for the main blog and user blogs are the same (as they are ultimately the same on the code level) and can be measured using the same metrics.  

Content migration

We are working on import scripts for external blog engines. We’ve started with importing blog content from Hubspot, and although it currently works on our servers only, it was a great proof of concept that showed how easily we can import external blog content from various sources. We are going to build a bulk create/update endpoint for Customizations that will enable our Channel Partners to build any import that is needed (e.g. Adobe Business Catalyst, Medium, Wordpress).

Installing the Blog Module


If you don’t have a Platform OS site yet, check out our quickstart guide and documentation to get you started. If you already have a Platform OS site, the easiest way to add a blog is to install it with our blog-module package that will add all necessary files to your directory structure.


Make sure you have npm installed and run:

npm i @platform-os/blog


The installer will prompt you for three variables:

  • blog url: where your blog will appear on your page

  • blog type: „Instance Blog” or „User Blog” to identify permissions to create/edit posts

  • blog layout name: passes the name of your layout if you want to skip the default one


If you use the default settings, you can access your blog settings under /blog/admin/settings.

Please note that you have to be logged in as an administrator to access the blog settings view.


Blog settings view



After filling out the blog settings, create your first blog post on the New post tab.





Once added, the post automatically appears on your post feed:




We hope this article gave you some valuable insight into how the Platform OS Blog Module works. Stay tuned for more articles about the concepts behind Platform OS and its different components, as well as useful resources like case studies, best practices, and guest posts from our community.

Interested in knowing more about partnering with platformOS?

Ensure your project’s success with the power of platformOS.