~askonomm/framework

WordPress theme development framework.
894818d7 — Asko Nõmm 8 months ago
Update README
6dca5512 — Asko Nõmm 8 months ago
Update README
35bd59ca — Asko Nõmm 8 months ago
2.6

refs

master
browse  log 

clone

read-only
https://git.sr.ht/~askonomm/framework
read/write
git@git.sr.ht:~askonomm/framework

You can also use your local clone with git send-email.

#Framework

A WordPress theme development framework that comes built with various helper methods as well as a templating system so you wouldn't have to scream at the awful mix of PHP & HTML that has haunted WordPress for ages.

#Install

  1. Download the latest version from releases.
  2. Upload the .zip file in your WordPress Admin > Plugins > Add New > Upload page.
  3. All good. You can now access all of the Framework PHP and JS methods.

Note: This plugin works with WordPress 5.3.2, PHP 7.4 and up.

Additionally there is also the Boilerplate if you wish to kickstart your theme development using Framework.

#Using Framework in PHP

Writing app logic happens in the functions.php file of the theme.

#First of all

Before you can begin to use Framework, initialize it first, like so:

$app = new Framework();

#Helper methods

#Initializing theme

You can initialize the theme with sensible defaults by calling the init method, like so:

$app->init();

This will load the sensible defaults as:

  • title-tag - Enabling WordPress itself to deal with the page titles
  • post-thumbnails - Adds post thumbnails support
  • html5 - Enables HTML5
  • automatic-feed-links - Adds automatic feed links
  • framework-js - Loads the Framework JS library

If you wish to exclude things from initializing, simply pass an array with keys of items to exclude, for example to exclude the title-tag, simply run the init like this:

$app->init(['title-tag']);
#Creating a navigation menu

To create a navigation menu, simply call the menu method. An example is:

$app->menu('primary-menu', 'Primary Menu');

Where the first argument takes the ID of the menu and the second argument the name of the menu.

#Adding scripts and styles

To enqueue scripts and styles in your theme, simply use the script and style methods. For example, to add a script to the <head> of your theme, simply do this:

$app->script('script-id', 'uri-to-script.js');

Likewise with the style:

$app->style('style-id', 'uri-to-style.css');
#Sending an e-mail

You can send an email via the sendEmail method, a fully configured example is:

$app->sendEmail('contact', [
  'to' => 'asko@digitalbaboon.com',
  'subject' => 'Contact Form | Digital Baboon',
  'name' => 'John Smith',
  'email' => 'john@smith.com',
  'companyName' => 'John Smith & Partners',
  'message' => 'Hi there!'
]);

The first argument is the template file name located in templates/emails/{filename}.hbs and the second argument is the data passed to the template. Note: the to and subject data keys are mandatory for the email sending to actually work, so you always need to pass those.

#Creating AJAX actions

You can create ajax actions with the ajaxAction method, a fully configured example is:

$app->ajaxAction('send_message', function() {

  // Do whatever you want here.
  // For example: call $app->sendMessage()

});

This would create the actions for both private and public ajax actions.

#Getting the current object

Getting the currently in scope object can be achieved with the current method, for example if you're on a tag page where the tag name is "Photos" then to get URL slug that represents it, you can do something like this:

$slug = $app->current()->slug; // returns "photos"

Likewise if you are on a post page and want to get the post ID, you can do this:

$id = $app->current()->ID;

If you want to do know percicely what it returns, just var_dump it in the context you need.

#Retrieving user input

To retrieve user input, you can use the input method, like so:

$name = $app->input('name');

This retrieves both $_GET and $_POST inputs as well as sanitizes them.

#Getting the current pagination number

To get the current pagination number, which is useful in a query, for example, call paged, like so:

$paged = $app->paged();
#Registering custom post types

To register a custom post type, call registePostType, like so:

$app->registerPostType('book', 'post', 'Book', 'Books', [
  'title',
  'editor',
  'author',
  'thumbnail',
  'excerpt',
  'trackbacks',
  'custom-fields',
  'comments',
  'revisions'
]);
  1. The first argument is the ID of the post type, the name by which you will programmatically call it.
  2. The second argument is the capability or type of the post type. It can be either post or page.
  3. The third argument is the singular name of the post type for use in the WordPress admin.
  4. The fourth argument is the plural name of the post type for use in the WordPress admin.
  5. The fifth argument is an array of features that the custom post type will support.
#Registering custom taxonomies

To register a custom taxonomy, call registerTaxonomy, like so:

$app->registerTaxonomy('book_categories', 'book', [

]);

The first argument is the taxonomy name in slug form, the second is the post type it should tie itself to and the third is an array of arguments that you can pass to the taxonomy.

#Conditional callbacks

In classic WordPress theme development you can use conditionals such as isFrontPage for the front page and isPage for the page to do logical work, you can do the same, but with callback functions. This is especially useful if used with Framework's templating, but you can use for whatever use case you may find as well.

#isFrontPage

To call a callback function when is_front_page conditional is true, do the following:

$app->isFrontPage(function() use($app) {

  // your code goes here.

});
#isHome

To call a callback function when is_home conditional is true, do the following:

$app->isHome(function() use($app) {

  // your code goes here.
  
});
#isPage

To call a callback function when is_page conditional is true, do the following:

$app->isPage('*', function() use($app) {

  // your code goes here.
  
});

Likewise replace * with the page slug, ID or array of them to fire the callback only on a specific page/pages.

#isSingle

To call a callback function when is_single conditional is true, do the following:

$app->isSingle('*', function() use($app) {

  // your code goes here.
  
});

Likewise replace * with the post slug, ID or array of them to fire the callback only on a specific post/posts.

#isCategory

To call a callback function when is_category conditional is true, do the following:

$app->isCategory('*', function() use($app) {

  // your code goes here.
  
});

Replace * with the category slug, ID or array of them to fire the callback only on a specific category/categories.

#isTag

To call a callback function when is_tag conditional is true, do the following:

$app->isTag('*', function() use($app) {

  // your code goes here.
  
});

Replace * with the tag slug, ID or array of them to fire the callback only on a specific tag/tags.

#isPostType

To call a callback function when is_post_type conditional is true, do the following:

$app->isPostType('post-type-slug', function() use($app) {

  // your code goes here.
  
});

Replace is-post-type-slug with the post type name in slug form.

#isPostTypeArchive

To call a callback function when is_post_type_slug conditional is true, do the following:

$app->isPostTypeArchive('post-type-slug', function() use($app) {

  // your code goes here.
  
});

Replace is-post-type-slug with the post type name in slug form.

#isArchive

To call a callback function when is_archive conditional is true, do the following:

$app->isArchive(function() use($app) {

  // your code goes here.
  
});
#isAuthor

To call a callback function when is_author conditional is true, do the following:

$app->isAuthor('*', function() use($app) {

  // your code goes here.
  
});

Likewise replace * with the author slug, ID or array of them to fire the callback only on a specific author/authors.

#isTax

To call a callback function when is_tax conditional is true, do the following:

$app->isTax('*', '*', function() use($app) {

  // your code goes here.
  
});

The first argument takes the taxonomy name, or asterisk (*) when matching any taxonomy, and the second argument takes the slug, ID or array of either of the terms in the taxonomy.

#isSearch

To call a callback function when is_search conditional is true, do the following:

$app->isSearch(function() use($app) {

  // your code goes here.
  
});
#is404

To call a callback function when is_404 conditional is true, do the following:

$app->is404(function() use($app) {

  // your code goes here.
  
});
#isUserLoggedIn

To call a callback function when is_user_logged_in conditional is true, do the following:

$app->isUserLoggedIn(function() use($app) {

  // your code goes here.
  
});

#Templating

If you wish to abandon the mess of mixing PHP with HTML, you can do so with Framework's templating system. To use the templating system, you need to first remove all PHP files from your theme directory (except functions.php and index.php, because we do our logic in functions.php and WordPress requires a index.php, but the index.php just leave empty).

Once you've done that, create a new directory called templates in your theme directory. In it, create a new directory called partials. Make sure you end up with a file structure like this:

  • templates/
    • partials/
  • index.php (empty file)
  • functions.php
  • style.css

You may guess where this is going. All new template files will be in the templates directory, with the partial files being in the partials directory. All templates are Handlebars files that end with the .hbs file extension.

#Getting started

In your functions.php file, let's define a route. For example, a route for the front page:

$app->isFrontPage(function() use($app) {

  // code that is here will be executed when is_front_page is true

});

This might look familiar to you. It's the same conditional you would use in traditional WordPress theme development, except in our case we provide it with a callback function that we execute when the conditional equals true.

Then, to actually display a Handlebars template on the front page of your site, call the template file, like so:

$app->isFrontPage(function() use($app) {

  $app->template('home');

});

This would load the template file located at templates/home.hbs. In it you can write whatever your heart desires. To pass information down to your template, simply add it to the template method, like so:

$app->isFrontPage(function() use($app) {

  $app->template('home', ['name' => 'John']);

});

And then you can display it in your home.hbs file this:

Hi, {{name}}

The rest of it works exactly like it should when it comes to Handlebars templating, so you can refer to its documentation for further help.

#Partials

Partials live in the {your-theme}/templates/partials folder. To register partials for use within your templates, you need to call registerTemplatePartials, like so:

$app->registerTemplatePartials([
  'header',
  'sidebar',
  'footer'
]);

You can then use these with {{> header}}, {{> sidebar}} and {{> footer}} in your Handlebars templates. You can register template partials within a scope of a route, such as inside the Conditional Callbacks so that the partials are only available within that context, but you can also register them globally if you do it outside the Conditional Callbacks which then would make the partials available globally.

#Helpers

There are currently these helpers available for use by default:

  • {{info "name"}} - usage of get_bloginfo()
  • {{menu "theme-location"}} - usage of wp_nav_menu()
  • {{meta "id" "key"}} - usage of get_post_meta()
  • {{date "format"}} - usage of date()
  • {{pagination "Prev" "Next" pages}} - usage of paginate_links (note the pages part, it comes from `query and you need to pass this along to pagination)

If you wish to register your own helpers for use within templates, you need to call registerTemplateHelpers, like so:

$app->registerTemplateHelpers([
  'greetings' => function($name) {
    return 'Hi, ' . $name;
  }
]);

You can use the helpers in your Handlebars template, like with the above example being the basis:

{{greetings "John"}}

There can of course be as many attributes as you wish.

#Variables

There are currently these variables available for use:

  • wp_head - prints the wp_head()
  • wp_footer - prints the wp_footer()
  • body_class - prints the body_class()
  • language_attributes - prints the language_attributes()
#Setting global template data

You can set global template data for use within all templates via the setTemplateData method, like so:

$app->setTemplateData([
  'name' = 'John'
]);

Based on this example you can now use the name variable in all the templates you use. This can greatly reduce duplicated code.

#Querying content

Since WP_Query isn't suitable for usage in a Handlebars template, we have a wrapper over WP_Query that returns data in a Handlebars-friendly way. So, let's say you want to display posts in your blog, you can do so like this:

$app->isHome(function() use($app) {

  $app->template('blog', [
    'posts' => $app->query(['post_type' => 'post'])
  ]);

});

Then in your .hbs file you would be able to do this:

{{#each posts}}

  <h2>{{title}}</h2>

  <div class="entry">{{{content}}}</div>

{{/each}}

List of available variables that come with the query are the following:

  • id - post ID
  • title - post title
  • url - post URL
  • published_at - post published date
  • author - post author
  • image - post thumbnail array
    • image.thumbnail - thumbnail size
    • image.small - small size
    • image.medium - medium size
    • image.large - large size
    • image.full - full size
  • has_tag - a boolean for if the post has a tag or not
  • tags - an array of tags
    • id - tag ID
    • name - tag name
    • url - tag URL
  • content - post content
  • pages - number of pages of this type of content (can be used for pagination)

#Extending

If there aren't enough features in Framework for you, feel free to extend it. You can do so by simply creating your own class that extends the Framework class, like so:

class App extends Framework {

  // your code here

}

This allows you to create as much cool stuff you want that would still all be accessible along with all the other stuff, like so:

$app = new App();

// now you can use $app to access the Framework methods as well as your own.

#Using Framework in JavaScript

#Creating AJAX actions

You can create AJAX actions with the ajaxAction method, a fully configured example is:

framework.ajaxAction('send_message', {
  name: 'John Smith',
  message: 'Hi there!'
}).then(response => {

  // Do something with response

}).catch(error => {

  // Do something with error

})

Keep in mind that this expects you to have set up an Ajax Action in the back-end. You can do that with the ajaxAction method in PHP, like stated in above documentation. Oh and, all ajaxActions are HTTP POST requests.