Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Statamic Add-ons

Building Statamic Add-ons

An overview to Statamic add-on development for the workshop at PeersConf 2014.

Jason Varga

April 23, 2014
Tweet

Other Decks in Programming

Transcript

  1. What makes an add-on? At least one of: » Plugins

    » Hooks » Tasks » Fieldtypes » Modifiers » API
  2. Plugins » Template tags {{ entries:listing }} » Single tags

    and tag pairs » Outputs string or performs a task » They can have parameters
  3. Tasks » Glue between the aspects of the add-on »

    All other add-on aspects can use tasks » Can be run automatically via cron » Important in keeping code DRY
  4. Tools at our disposal » Statamic’s Internal API » Add-on

    class methods » Bundles » Documentation » PHP.net
  5. Statamic's Internal API » Abstracted helper methods Content::getFoldersByURL(‘ blog’); »

    api.statamic.com Don’t use it » Look in the code. Don’t be scared of the /_app/ folder
  6. Add-on class methods » Further abstracted methods Session::set('karma', 'var', $val);

    $this->session->set('var', $val); » /_app/core/extend/
  7. Add-on » Every aspect extends the Addon class » Its

    methods are available to every aspect » $this->config, $this- >fetchConfig » $this->log, cache, css, js, asset, addon
  8. class Plugin_hello_world extends Plugin { public function index() { $name

    = $this->fetchParam('name', 'world'); return 'Hello '.$name.'!'; } } {{ hello_world name="Jack" }} => Hello Jack! {{ hello_world }} => Hello world!
  9. Hooks » You hook into other events » You don’t

    create the hooks » Using /TRIGGER/ is just using a Statamic Hook » You can create a hook, but it can be from anywhere.
  10. class Hooks_hello_world extends Hooks { public function hello_world__shout() { $name

    = array_get($_POST', 'name', 'world'); exit( 'Hello '.$name.'!' ); } } POST to: http://mysite.com/TRIGGER/hello_world/shout => Hello world!
  11. From the core: $app->map( '/TRIGGER/:namespace/:hook(/:segments+)', function ($namespace, $hook, $segments =

    array()) use ($app) { Hook::run($namespace, $hook, null, null, $segments); })->via('GET', 'POST', 'HEAD');
  12. Tasks » Any automation requires a define() method » $this->add(5,

    ’foo’) will run foo every 5 mins » To enable, enter this in crontab: * * * * * curl --silent http://example.com/TRIGGER/tasks/tick > /dev/null 2>&1 » Tasks can be called within define() automatically or with $this->tasks->method()
  13. class Tasks_reminders extends Tasks { public function define() { $this->add(1440,

    'sendReminders'); } public function sendReminders() { // send emails } } class Hooks_reminders extends Hooks { public function reminders__send() { $this->tasks->sendReminders(); } }
  14. Fieldtype » Unlimited config options » $this->field_config, field_data, fieldname »

    Ascent is your friend » CSS is reusable – wow! » JS libraries in Ascent are available to you (jQuery, underscore.js, knockout.js) » Not limited to saving to one field
  15. class Fieldtype_text extends Fieldtype { public function render() { $type

    = array_get($this->field_config, 'input_type', 'text'); $attributes = array( 'name' => $this->fieldname, 'id' => $this->field_id, 'tabindex' => $this->tabindex, 'value' => HTML::convertSpecialCharacters($this->field_data) ); return HTML::makeInput($type, $attributes, $this->is_required); } }
  16. class Hooks_text extends Hooks { public function control_panel__add_to_foot() { if

    (URL::getCurrent() == '/publish') { return $this->js->link('text'); } } }
  17. class Modifier_slugify extends Modifier { public function index($value, $parameters=array()) {

    $delimiter = array_get($parameters, 0, '-'); return Slug::make($value, array('delimiter' => $delimiter)); } } thing: this is a thing {{ thing|slugify }} => this-is-a-thing {{ thing|slugify:* }} => this*is*a*thing
  18. class Modifier_slugify extends Modifier { public function index($value, $parameters=array()) {

    $parameters = explode(',', array_get($parameters, 0, array())); $first_param = $parameters[0]; $second_param = $parameters[1]; // return ... } }
  19. File Based Cache » For stuff that will be sticking

    around. » Mainly used for content » Lives in /_cache/_add-ons/addon_name/ » Store anything, it's just text » YAML makes your life easier
  20. This: $name = 'foobar'; $stuff = array( 'foo' => 'one',

    'bar' => 'two', 'arr' => array( 'one' => 'uno', 'two' => 'dos' ) ); $this->cache->putYAML("stuff/$name", $stuff); // Saves to: /_cache/_add-ons/my_addon/stuff/foobar
  21. Becomes this: foo: one bar: two arr: one: uno two:

    dos Read it with this: $this->cache->getYAML("stuff/foobar");
  22. Cookie Based Cache » Saved to the user's browser »

    Read/write with JavaScript » Users can erase it
  23. {{ entries:listing folder="blog" since="2 weeks ago" sort_by="author" }} ... {{

    /entries:listing }} {{ entries:pagination folder="blog" since="2 weeks ago" sort_by="author" }} ... {{ /entries:pagination }}
  24. Manipulating Content » Don't need to reinvent the wheel »

    Use ContentService to get a ContentSet » ContentSets can be filtered and sorted
  25. // Grab all the content $content_set = ContentService::getContentByFolders('blog|events'); // Filter

    it $content_set->filter(array( 'type' => 'entries', 'show_past' => true, 'show_future' => true )); // Get it $content_set->get();
  26. Creating an add-on » Analyze the brief » Scaffold »

    Fill in the gaps » Optimize & Simplify » Document
  27. Karma » Members can assign points to other members »

    Display a points leaderboard » Pages can require points for access » A member can view a list of pages they can access » Reset points every week
  28. Bluebird » Ability to select a tweet » Ability to

    convert a tweet status ID » Speed things up by adding caching