Extending CMS Made Simple
              Presented by
    Jeff Bosch and Samuel Goldstein
Jeff Bosch
●   Core Development Team member
●   B.S. in Computer Science
●   Started A & J Progamming in 2007 for
    cust...
Samuel Goldstein
●   Core Development Team member since 2004
●   Principal at 1969 Communications
●   Background
    ●   P...
OK, enough of that
●   Why extend CMS Made Simple?
    ●   Add functionality
    ●   Make things easier for your clients
 ...
Ways to Extend CMSMS
●   Core, core modules, and Smarty
●   User-Defined Tags
●   Tags (a.k.a. Plugins)
●   Modules
How do I decide on an
             approach?
●   There is not always an “absolute best”
    approach
●   Don't neglect non...
Approaches


                                              Smarty   Tag   UDT   Module
No installation required           ...
Let's get started!
●   Build a Google Site Map using Core and
    Core Modules
    ●   We'll use Menu Manager in a hidden ...
Menu Manager Template


<?xml  version="1.0"  encoding="UTF-­‐8"?>
<urlset  xmlns="hRp://www.sitemaps.org/schemas/sitemap/...
Calling the Template
●   Create page named “sitemap”
●   Set alias to “sitemap” too
●   Uncheck “Show in Menu”
●   Insert ...
Add an .htaccess file


<IfModule  mod_rewrite.c>
RewriteEngine  on
#Sub-­‐dir  e.g:  /cmsms
RewriteBase  /
RewriteCond  %{...
Test it!
●   Go to http://yoursite.com/sitemap.xml
<?xml  version="1.0"  encoding="UTF-­‐8"?>
<urlset  xmlns="hRp://www.si...
OK, how about a Tag?
●   Only tags can serve as Smarty modifiers
●   Here's a tag that vigorously defends our
    intellect...
postfilter.registeredtrademarker.php

<?php
funcQon  smarty_cms_posPilter_registeredtrademarker($tpl_output,  &$smarty)
{
 ...
Using the Filter
●   Save your filter in the plugins directory
●   In the Admin, be sure to clear your
    cache!
●   View ...
You® filte®ed ®esults
OK, how about a UDT?
●   UDTs can do all sorts of things:
    ●   Talk to the database
    ●   Talk to modules
    ●   Dea...
UDT “pagecounter”
global  $gCms;

$db  =  $gCms-­‐>GetDb();

$count  =  $db-­‐>GetOne('select  count(*)  from  '.cms_db_pr...
Then, add a content page
●   Set the title and menu text
●   In the content, call the UDT with
{pagecounter}

●   And outp...
Viewing your page
Exercise I
●   What approach would you use to implement each
    of the following?
    ●   Convert your page content into ...
Exercise I, cont.
●   Display a special image file only on the site's
    home page
●   Display the Admin account email add...
Exercise II
●   Create a UDT for changing site layout
    seasonally.
    ●   Set a variable which can be used to change
 ...
Exercise II, cont. UDT
global  $gCms;

$month  =  date('n');  //  returns  month  as  number  between  1  and  12,  inclus...
Exercise II, cont. Template.
{process_pagedata}
<!DOCTYPE  html  PUBLIC  "-­‐//W3C//DTD  XHTML  1.0  TransiQ onal//EN"  
"...
Exercise II, cont. CSS
.winter  {background-­‐color:  #bfc4ff;}
.spring  {background-­‐color:  #bfffce;}
.summer  {backgroun...
Hour II
How's my timing?
Getting Started with Modules
●   For the 1.x series, several ways to get
    started
    ●   From scratch
    ●   Skeleton...
Skeleton Module
●   Download from Forge or Module
    Manager
●   Has simple functionality
    ●   install/upgrade
    ●  ...
Skeleton Module, cont.
●   Once you've installed, edit the files to
    adapt to your own purposes
●   Well commented
●   S...
Structure of a 1.x module
●   Modules extend the CMSModule class
●   Magic of OO:
    ●   Automatically inherits a lot of ...
Minimal 1.x Module
●   File lives in
    $CMS_ROOT/modules/module_name
●   Filename is module_name.module.php
●   Module c...
Minimal 1.x module, cont.
●   GetName simply returns module name;
    must match class and filename
●   IsPluginModule retu...
DoAction
●   Called with a few parameters:
    ●   $action, “reason for calling.” Two built-in:
        “default” and “def...
Other important methods
●   Install, upgrade, uninstall. These methods
    called as expected, and allow for
    housekeep...
Minimal 1.x module, cont.
●   For performance reasons, methods are
    split out into multiple files
●   String translation...
Layout on filesystem
Enough Abstraction!
●   We will create a basic module that
    demonstrates core APIs
●   “Quotations Module” requirements...
Step 1. Preparation
●   Create directories
    ●   $CMS_ROOT/modules/Quotations
    ●   Quotations/templates
    ●   Quota...
Quotations.module.php
<?php
class  QuotaQons  extends  CMSModule
       {
       funcQon  GetName()
            {
        ...
lang/en_US.php
<?php
$lang['friendlyname']='QuotaQon  Module';
?>
Database Schema
●   We'll probably need
    ●   Unique ID
    ●   Quotation text
    ●   Quotation author
    ●   Submissi...
method.install.php
<?php
if  (!isset($gCms))  exit;

$db  =  $this-­‐>GetDb();
$dict  =  NewDataDicQonary(  $db  );

$field...
Install it
Consider parameters
●   Form will submit quotation and author
●   Viewing will require quotation_id
●   Module will also b...
SetParameters()
funcQon  SetParameters()
    {
    $this-­‐>RegisterModulePlugin();
    $this-­‐>RestrictUnknownParams();
...
Viewing Module Help
OK, let's get serious.
●   Need to create the form
●   Need to handle the inputs
●   This will be the module's default act...
action.default.php
<?php
if  (!isset($gCms))  exit;

$smarty-­‐>assign('form_start',$this-­‐>CreateFormStart($id,  'defaul...
user_form.tpl
<div  class="quotaQon_form">
      {$form_start}
      <div>{$input_author}</div>
      <div>{$Qtle_quotaQon...
Add the tag to a page
View the page
Update our lang file
<?php
$lang['friendlyname']='QuotaQon  Module';

$lang['Qtle_author']='QuotaQon  Author';
$lang['Qtle_...
And check again
Input validation
Added to top of action.default.php
if  (isset($params['submit']))
        {
        if  (empty($params['a...
Try an empty submit
Store to database
if  (isset($params['submit']))
        {
        if  (empty($params['author'])  ||  empty($params['quota...
Test it – add a quotation
action.display.php
<?php
if  (!isset($gCms))  exit;

$db=$this-­‐>GetDb();
$row  =  array();
$res  =  $db-­‐>Execute('sele...
display_quotation.tpl
<dl>
     <dd>{$quotaQon.quotaQon}</dd>
     <dt>{$quotaQon.author}</dt>
</dl>
Add the tag to page template
●   Find a convenient spot
●   Add the tag:
{QuotaQons  acQon='display'}
Try it!
2.0 Module API
2.0  Module  Extensions:

Database:
    create_table($table,  $fields)
    create_index($table,  $name,  $fie...
method.install.php
<?php
if  (!isset($gCms))  exit;

$this-­‐>Database-­‐>create_table('module_quotaQ ons',  "
     quotaQ...
2.0 Module API
2.0 Module Extensions (Group 2)

Permission:
   create($permission_name, $extra_attr = '', $hierarchical = ...
action.default.php
<?php
if  (!isset($gCms))  exit;

$smarty-­‐>assign('form_start',$this-­‐>Form-­‐
>form_start(array('ac...
2.0 Smarty Tags
{has_permission  perm="Modify  Templates"}
{/has_permission}

{tabs}
    {tab_content  name='users'}
     ...
Blocks:  2.0 Module Smarty Tags
    {mod_form}{/mod_form}
    {mod_formrow}{/mod_formrow}
    {mod_label}{/mod_label}
    ...
2.0 Module Form
{mod_validaQon_errors  for=$blog_post}

{mod_form  acQon=$form_acQon}
         {mod_label  name="blog_post...
2.0 Module Form (Part 2)
        {mod_label  name='post_date_Month'}{tr}Post  Date{/tr}{/mod_label}:<br  />
        {html_...
OK, let's add an admin panel
●   First, we need to add a permission to
    control access
●   This should be done in the i...
method.install.php
<?php
if  (!isset($gCms))  exit;
$db  =  $this-­‐>GetDb();
$dict  =  NewDataDicQonary(  $db  );

$fields...
method.upgrade.php
<?php
if  (!isset($gCms))  exit;

switch($old_version)
     {
     case  "0.1":
           $this-­‐>Cre...
Perform the upgrade
Now implement admin panel
              1.x
●   Add method to main module:
     function HasAdmin()
         {
         re...
action.defaultadmin.php
<?php
if  (!isset($gCms))  exit;
if  (!$this-­‐>CheckPermission('Manage  QuotaQons'))  exit;

$db=...
admin_display_list.tpl
{if  isset($message)  &&  $message!=''}<div  class="pagewarning">{$message}</div>{/if}
<table>
{for...
Admin View
action.admin_delete.php
<?php
if  (!isset($gCms))  exit;
if  (!$this-­‐>CheckPermission('Manage  QuotaQons'))  exit;

if  ...
Delete Quotation
Be kind to users


●   Add some safety – modify default admin
    link to delete
$row['delete']  =  $this-­‐>CreateLink($i...
That's better
Let admin edit quotations
●   We can re-use the form template
●   Just need to create the admin-side logic
●   Note that t...
action.admin_edit.php
<?php
if  (!isset($gCms))  exit;
if  (!$this-­‐>CheckPermission('Manage  QuotaQ ons'))  exit;
$db  =...
action.admin_edit.php, cont
     {
     $res  =  $db-­‐>Execute('select  *  from  '.cms_db_prefi x().'module_quotaQons  whe...
Editing
And edited
action.defaultadmin.php 2.0
if  (!isset($gCms))  die("Can't  call  acQons  directly!");

if  (  !$this-­‐>Permission-­‐>ch...
defaultadmin.tpl 2.0
{has_permission  perm="Modify  Templates"}
     <div  style="text-­‐align:  right;  width:  80%;"><a ...
Upcoming SlideShare
Loading in …5
×

Extending CMS Made Simple

20,847 views

Published on

How to add functionality to CMS Made Simple using Tags, User-Defined Tags, and Modules. Also includes some previews of how the module API will change with version 2.0

Published in: Technology
  • Very nice and clear tutorials...
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Extending CMS Made Simple

  1. 1. Extending CMS Made Simple Presented by Jeff Bosch and Samuel Goldstein
  2. 2. Jeff Bosch ● Core Development Team member ● B.S. in Computer Science ● Started A & J Progamming in 2007 for custom web programming and implementation
  3. 3. Samuel Goldstein ● Core Development Team member since 2004 ● Principal at 1969 Communications ● Background ● Programming since 1980, starting with TRS-80 ● Aerospace in the '90s ● Dot-com roller coaster ● Hey! Buy my book! ● CMS Made Simple Developer's Cookbook from Packt Publishing
  4. 4. OK, enough of that ● Why extend CMS Made Simple? ● Add functionality ● Make things easier for your clients ● More money for you ● Fame, fortune, glory
  5. 5. Ways to Extend CMSMS ● Core, core modules, and Smarty ● User-Defined Tags ● Tags (a.k.a. Plugins) ● Modules
  6. 6. How do I decide on an approach? ● There is not always an “absolute best” approach ● Don't neglect non-technical considerations (e.g., your specific users) ● The following chart may also help
  7. 7. Approaches Smarty Tag UDT Module No installation required √ √ Multiple actions √* √ Create databases / preferences √* √ Act as Smarty modifier √ Help displayed in Admin area √ √ Admin panel √ Post on Developer's Forge, share via Module √ Manager Localization/Translation √
  8. 8. Let's get started! ● Build a Google Site Map using Core and Core Modules ● We'll use Menu Manager in a hidden page ● We'll create a custom Menu Manager template ● And a mod_rewrite trick
  9. 9. Menu Manager Template <?xml  version="1.0"  encoding="UTF-­‐8"?> <urlset  xmlns="hRp://www.sitemaps.org/schemas/sitemap/0.9"> {if  $count  >  0} {foreach  from=$nodelist  item=node}  <url>        <loc>{$node-­‐>url|escape:'html'}</loc>        <lastmod>{$node-­‐>modified|date_format:'%Y-­‐%m-­‐%dT%T-­‐08:00'}</lastmod>    </url> {/foreach} {/if} </urlset>
  10. 10. Calling the Template ● Create page named “sitemap” ● Set alias to “sitemap” too ● Uncheck “Show in Menu” ● Insert tag into your page content: {menu  template='sitemap'  show_all='1'  collapse='0'}
  11. 11. Add an .htaccess file <IfModule  mod_rewrite.c> RewriteEngine  on #Sub-­‐dir  e.g:  /cmsms RewriteBase  / RewriteCond  %{REQUEST_FILENAME}  !-­‐f  [NC] RewriteCond  %{REQUEST_FILENAME}  !-­‐d  [NC] RewriteRule  ^sitemap.xml$  index.php?page=sitemap&showtemplate=false  [L] </IfModule>
  12. 12. Test it! ● Go to http://yoursite.com/sitemap.xml <?xml  version="1.0"  encoding="UTF-­‐8"?> <urlset  xmlns="hRp://www.sitemaps.org/schemas/sitemap/0.9">    <url>        <loc>hRp://cms_book.viajante/</loc>        <lastmod>2009-­‐05-­‐13T10:12:18-­‐08:00</lastmod>    </url>    <url>        <loc>hRp://cms_book.viajante/index.php?page=how-­‐cmsms-­‐works</loc>        <lastmod>2009-­‐05-­‐12T20:11:52-­‐08:00</lastmod>    </url>  … </urlset>
  13. 13. OK, how about a Tag? ● Only tags can serve as Smarty modifiers ● Here's a tag that vigorously defends our intellectual property! ● Appends a ® symbol to every instance of “CMS Made Simple” in page content.
  14. 14. postfilter.registeredtrademarker.php <?php funcQon  smarty_cms_posPilter_registeredtrademarker($tpl_output,  &$smarty) { global  $gCms; $result  =  explode(':',  $smarty-­‐>_current_file); if  (count($result)  >  0) { if  ($result[0]  ==  'content') { $tpl_output  =  str_replace('CMS  Made  Simple','CMS  Made  Simple®',  $tpl_output); } } return  $tpl_output; } ?>
  15. 15. Using the Filter ● Save your filter in the plugins directory ● In the Admin, be sure to clear your cache! ● View your site.
  16. 16. You® filte®ed ®esults
  17. 17. OK, how about a UDT? ● UDTs can do all sorts of things: ● Talk to the database ● Talk to modules ● Deal with events ● Interact with Smarty ● Let's try a few of those things!
  18. 18. UDT “pagecounter” global  $gCms; $db  =  $gCms-­‐>GetDb(); $count  =  $db-­‐>GetOne('select  count(*)  from  '.cms_db_prefi x().'content  where  acQve=1'); $smarty  =  $gCms-­‐>GetSmarty(); $smarty-­‐>assign('page_count','Total  pages:  '.$count);
  19. 19. Then, add a content page ● Set the title and menu text ● In the content, call the UDT with {pagecounter} ● And output the Smarty variable with {$page_count}
  20. 20. Viewing your page
  21. 21. Exercise I ● What approach would you use to implement each of the following? ● Convert your page content into Pirate Speak ● A form for users to submit movie reviews, with an Admin panel allowing the site maintainer to approve or reject reviews for display ● Putting the title of the most-recently added page into a Smarty variable
  22. 22. Exercise I, cont. ● Display a special image file only on the site's home page ● Display the Admin account email address on a page (but obscured to prevent spammers from harvesting it) ● Display a poll, and show the results after the user votes ● Display links to all pages that are below the current page in the site hierarchy
  23. 23. Exercise II ● Create a UDT for changing site layout seasonally. ● Set a variable which can be used to change the stylesheet classes of the site. ● For simplicity, call January-March “winter,” April-June “spring,” July-September “summer,” and October-December “autumn.”
  24. 24. Exercise II, cont. UDT global  $gCms; $month  =  date('n');  //  returns  month  as  number  between  1  and  12,  inclusive $smarty  =  $gCms-­‐>GetSmarty(); if  ($month  <  4) $season  =  'winter'; else  if  ($month  <  7) $season  =  'spring'; else  if  ($month  <  10) $season  =  'summer'; else $season  =  'autumn'; $smarty-­‐>assign('season',  $season);
  25. 25. Exercise II, cont. Template. {process_pagedata} <!DOCTYPE  html  PUBLIC  "-­‐//W3C//DTD  XHTML  1.0  TransiQ onal//EN"   "hRp://www.w3.org/TR/xhtml1/DTD/xhtml1-­‐transiQ onal.dtd"> <html  xmlns="hRp://www.w3.org/1999/xhtml"  xml:lang="en"  > <head> <Qtle>{sitename}  -­‐  {Qtle}</Qtle> {metadata} {cms_stylesheet} {season} </head> <body> <div  id="header"><h1  class=”{$season}”>{sitename}</h1></div> <div  id="menu">{menu}</div> <div  id="content"  class=”{$season}”>    <h1>{Qtle}</h1>    {content} </div> </body> </html>
  26. 26. Exercise II, cont. CSS .winter  {background-­‐color:  #bfc4ff;} .spring  {background-­‐color:  #bfffce;} .summer  {background-­‐color:  #fffabf;} .autumn  {background-­‐color:  #ffcabf;} #header  h1.summer  {background:  url(/uploads/images/beach.jpg);}
  27. 27. Hour II How's my timing?
  28. 28. Getting Started with Modules ● For the 1.x series, several ways to get started ● From scratch ● Skeleton module ● Module Maker ● MCFactory ● etc
  29. 29. Skeleton Module ● Download from Forge or Module Manager ● Has simple functionality ● install/upgrade ● admin panel ● database routines ● form API calls
  30. 30. Skeleton Module, cont. ● Once you've installed, edit the files to adapt to your own purposes ● Well commented ● Somewhat dated: last updated for CMS MS 1.6.5 ● Still has correct structure, but may lack more recent improvements and features
  31. 31. Structure of a 1.x module ● Modules extend the CMSModule class ● Magic of OO: ● Automatically inherits a lot of functionality (e.g., Database and Form APIs, Smarty, Translation, etc) ● Most methods already inherit acceptable defaults
  32. 32. Minimal 1.x Module ● File lives in $CMS_ROOT/modules/module_name ● Filename is module_name.module.php ● Module class must match file name ● Need to implement 3 methods: ● GetName ● DoAction ● IsPluginModule
  33. 33. Minimal 1.x module, cont. ● GetName simply returns module name; must match class and filename ● IsPluginModule returns boolean. ● DoAction is, unsurprisingly, where the real action takes place
  34. 34. DoAction ● Called with a few parameters: ● $action, “reason for calling.” Two built-in: “default” and “defaultadmin” ● $id, a prefix for use in forms ● $params, a hash of parameters ● $returnid, reference to the page containing the tag
  35. 35. Other important methods ● Install, upgrade, uninstall. These methods called as expected, and allow for housekeeping ● SetParameters. Sets up parameter filtering, URL routes, ● Lang. Translates strings.
  36. 36. Minimal 1.x module, cont. ● For performance reasons, methods are split out into multiple files ● String translations are stored in external files ● Templates may be stored as files or in the database
  37. 37. Layout on filesystem
  38. 38. Enough Abstraction! ● We will create a basic module that demonstrates core APIs ● “Quotations Module” requirements: ● Presents form to user, handles input safely ● Displays random quotation to user ● Allows admin to delete records
  39. 39. Step 1. Preparation ● Create directories ● $CMS_ROOT/modules/Quotations ● Quotations/templates ● Quotations/lang ● Create base files: ● Quotations.module.php ● lang/en_US.php
  40. 40. Quotations.module.php <?php class  QuotaQons  extends  CMSModule { funcQon  GetName() { return  'QuotaQons'; } funcQon  GetFriendlyName() { return  $this-­‐>Lang('friendlyname'); } funcQon  IsPluginModule() { return  true; } funcQon  GetVersion() { return  '0.1'; } } ?>
  41. 41. lang/en_US.php <?php $lang['friendlyname']='QuotaQon  Module'; ?>
  42. 42. Database Schema ● We'll probably need ● Unique ID ● Quotation text ● Quotation author ● Submission date
  43. 43. method.install.php <?php if  (!isset($gCms))  exit; $db  =  $this-­‐>GetDb(); $dict  =  NewDataDicQonary(  $db  ); $fields=" quotaQon_id  I  KEY, quotaQon  X, author  C(80), submit_date  DT "; $sqlarray  =  $dict-­‐>CreateTableSQL(  cms_db_prefix()."module_quotaQons",$fields); $dict-­‐>ExecuteSQLArray($sqlarray); $db-­‐>CreateSequence(cms_db_prefix()."module_quotaQon_seq"); ?>
  44. 44. Install it
  45. 45. Consider parameters ● Form will submit quotation and author ● Viewing will require quotation_id ● Module will also be a plugin module, so we want to give it its own tag {quotation} ● Let's create SetParameters method
  46. 46. SetParameters() funcQon  SetParameters() { $this-­‐>RegisterModulePlugin(); $this-­‐>RestrictUnknownParams(); $this-­‐>CreateParameter('quotaQon_id','null',$this-­‐>Lang('help_quotaQ on_id')); $this-­‐>SetParameterType('quotaQon_id',  CLEAN_INT); $this-­‐>CreateParameter('author','anonymous',$this-­‐>Lang('help_author')); $this-­‐>SetParameterType('author',CLEAN_STRING); $this-­‐>CreateParameter('quotaQon','',$this-­‐>Lang('help_quotaQon')); $this-­‐>SetParameterType('quotaQon',CLEAN_STRING); $this-­‐>CreateParameter('submit'); $this-­‐>SetParameterType('submit',CLEAN_STRING); } funcQon  GetHelp() { return  $this-­‐>Lang('help'); }
  47. 47. Viewing Module Help
  48. 48. OK, let's get serious. ● Need to create the form ● Need to handle the inputs ● This will be the module's default action ● Create action.default.php
  49. 49. action.default.php <?php if  (!isset($gCms))  exit; $smarty-­‐>assign('form_start',$this-­‐>CreateFormStart($id,  'default',  $returnid)); $smarty-­‐>assign('input_author',$this-­‐>CreateInputTextWithLabel($id,  'author', isset($params['author'])?$params['author']:'',  10,  80,  '', $this-­‐>Lang('Qtle_author'))); $smarty-­‐>assign('Qtle_quotaQon',$this-­‐>Lang('Qtle_quotaQon')); $smarty-­‐>assign('input_quotaQon',$this-­‐>CreateTextArea(false,  $id, isset($params['quotaQon'])?html_enQty_decode($params['quotaQon'],ENT_QUOTES):'',   'quotaQon')); $smarty-­‐>assign('submit',$this-­‐>CreateInputSubmit($id,  'submit',  $this-­‐>Lang('submit'))); echo  $this-­‐>ProcessTemplate('user_form.tpl'); ?>
  50. 50. user_form.tpl <div  class="quotaQon_form"> {$form_start} <div>{$input_author}</div> <div>{$Qtle_quotaQon}<br  />{$input_quotaQon}</div> <div>{$submit}</div> </form> </div>
  51. 51. Add the tag to a page
  52. 52. View the page
  53. 53. Update our lang file <?php $lang['friendlyname']='QuotaQon  Module'; $lang['Qtle_author']='QuotaQon  Author'; $lang['Qtle_quotaQon']='QuotaQon'; $lang['submit']='Submit'; $lang['help_quotaQon_id']='ID  for  a  specific  quotaQon'; $lang['help_author']='QuotaQon  author'; $lang['help_quotaQon']='QuotaQon  text'; $lang['help']='This  module  is  for  the  presentaQon  of  quotaQons.'; ?>
  54. 54. And check again
  55. 55. Input validation Added to top of action.default.php if  (isset($params['submit'])) { if  (empty($params['author'])  ||  empty($params['quotaQ on'])) { $smarty-­‐>assign('message',$this-­‐>Lang('error_empty_fi elds')); } } Added to user_form.tpl {if  isset($message)  &&  $message!=''}<div  class="error">{$message}</div>{/if}
  56. 56. Try an empty submit
  57. 57. Store to database if  (isset($params['submit'])) { if  (empty($params['author'])  ||  empty($params['quotaQ on'])) { $smarty-­‐>assign('message',$this-­‐>Lang('error_empty_fi elds')); } else { $db  =  $this-­‐>GetDb(); $quotaQon_id  =  $db-­‐>GenID(cms_db_prefix().  'module_quotaQon_seq'); $res  =  $db-­‐>Execute('insert  into  '.cms_db_prefi x(). 'module_quotaQons  (quotaQon_id,author,quotaQon,submiRed_date)  values  (?,?,?,NOW())', array($quotaQon_id,$params['author'],$params['quotaQon'])); if  ($res  ===  false) { $smarty-­‐>assign('message',$this-­‐>Lang('db_error',$db-­‐>ErrorMsg())); } else { $smarty-­‐>assign('message',$this-­‐>Lang('added')); } } }
  58. 58. Test it – add a quotation
  59. 59. action.display.php <?php if  (!isset($gCms))  exit; $db=$this-­‐>GetDb(); $row  =  array(); $res  =  $db-­‐>Execute('select  *  from  '.cms_db_prefix(). 'module_quotaQons  order  by  rand()  limit  1'); if  ($res  &&  $row=$res-­‐>FetchRow()) { $smarty-­‐>assign('quotaQon',$row); } echo  $this-­‐>ProcessTemplate('display_quotaQ on.tpl'); ?>
  60. 60. display_quotation.tpl <dl> <dd>{$quotaQon.quotaQon}</dd> <dt>{$quotaQon.author}</dt> </dl>
  61. 61. Add the tag to page template ● Find a convenient spot ● Add the tag: {QuotaQons  acQon='display'}
  62. 62. Try it!
  63. 63. 2.0 Module API 2.0  Module  Extensions: Database: create_table($table,  $fields) create_index($table,  $name,  $field) drop_table($table) Preference:   get($preference_name,  $default_value  =  '') set($preference_name,  $value) remove($preference_name  =  '') Template:   get_list($template_type  =  '') get($template_type,  $template_name) get_from_file($template_name) set($template_type,  $template_name,  $content,  $default  =  null) delete($template_type  =  '',  $template_name  =  '') process_from_data(  $data  ) process_from_database($template_type,  $template_name  =  '',  $id  =  '',  $return_id  =  '',   $designaQon  =  '',  $cache_id  =  '') process($template_name,  $id  =  '',  $return_id  =  '',  $designaQ on  =  '',  $cache_id  =  '')
  64. 64. method.install.php <?php if  (!isset($gCms))  exit; $this-­‐>Database-­‐>create_table('module_quotaQ ons',  " quotaQon_id  I  KEY  AUTO, language  C(8), quotaQon  X, author  C(80), submiRer  C(80), submit_date  DT "); $this-­‐>Database-­‐>create_index('module_quotaQ ons','Author',  'author'); $this-­‐>Template-­‐>set('summary',  'Default  Template',  $this-­‐>Template-­‐ >get_from_file('orig_default_summary')); $this-­‐>Preference-­‐>set('sort_by','author'); $this-­‐>Permission-­‐>create('Manage  QuotaQons'  ); ?>
  65. 65. 2.0 Module API 2.0 Module Extensions (Group 2) Permission: create($permission_name, $extra_attr = '', $hierarchical = false, $table = '') check($permission_name, $extra_attr = '', $hierarchical = false, $table = '') remove($permission_name, $extra_attr = '') Form: form_start($params = array(), $check_keys = false) form_end input_text input_hidden input_checkbox input_submit input_select input_options input_textarea Redirect: module_url Url: link content_linkreturn_link
  66. 66. action.default.php <?php if  (!isset($gCms))  exit; $smarty-­‐>assign('form_start',$this-­‐>Form-­‐ >form_start(array('acQon'=>'default','return_id'=>$returnid))  ); $smarty-­‐>assign('input_author',$this-­‐>Form-­‐>input_text(array('id'=>$id,'name'=>   'author','value'=> isset($params['author'])?$params['author']:'',  'size'=>10,'maxlength=>80,   'lable'=>'Qtle_author'))  ); $smarty-­‐>assign('Qtle_quotaQon',$this-­‐>Lang('Qtle_quotaQon')); $smarty-­‐>assign('submit',$this-­‐>Form-­‐>input_submit('name'=>  'submit',  'value'=>'submit'))); echo  $this-­‐>Template-­‐> process_from_database ('summary'); ?>
  67. 67. 2.0 Smarty Tags {has_permission  perm="Modify  Templates"} {/has_permission} {tabs} {tab_content  name='users'} {tab_header  name='users'} {/tab_header} {/tab_content} {/tabs} {tr}users{/tr}
  68. 68. Blocks: 2.0 Module Smarty Tags {mod_form}{/mod_form} {mod_formrow}{/mod_formrow} {mod_label}{/mod_label} {mod_select}{/mod_select} FuncQons: {mod_checkbox} {mod_dropdown} {mod_helptext} {mod_hidden} {mod_lang} {mod_link} {mod_opQons} {mod_password} {mod_submit} {mod_template} {mod_textarea} {mod_textbox} {mod_validaQon_errors}
  69. 69. 2.0 Module Form {mod_validaQon_errors  for=$blog_post} {mod_form  acQon=$form_acQon} {mod_label  name="blog_post[Qtle]"}Title{/mod_label}:<br  /> {mod_textbox  name="blog_post[Qtle]"  value=$blog_post-­‐>Qtle  size="40"} {mod_label  name="blog_post[content]"}Post{/mod_label}:<br  /> {mod_textarea  name="blog_post[content]"  value=$blog_post-­‐>content  cols="40"   rows="10"  wysiwyg=true} <legend>{tr}Categories{/tr}</legend> {foreach  from=$categories  item='one_category'} {assign  var=category_id  value=$one_category-­‐>id} {assign  var=category_name  value=$one_category-­‐>name} {mod_checkbox  name="blog_post[category][$category_id]"   selected=$blog_post-­‐>in_category($category_id)}  {$category_name}<br  /> {/foreach} {mod_label  name="blog_post[status]"}{tr}Status{/tr}{/mod_label}:<br  /> {mod_dropdown  name="blog_post[status]"  items=$cms_mapi_module-­‐>get_statuses()   selected_value=$blog_post-­‐>status}
  70. 70. 2.0 Module Form (Part 2) {mod_label  name='post_date_Month'}{tr}Post  Date{/tr}{/mod_label}:<br  /> {html_select_date  prefix=$post_date_prefix  Qme=$blog_post-­‐>post_date-­‐ >Qmestamp()  start_year=2000  end_year=2020}  {html_select_Q me  prefix=$post_date_prefix   Qme=$blog_post-­‐>post_date-­‐>Qmestamp()} {mod_hidden  name="blog_post[author_id]"  value=$blog_post-­‐>author_id} {mod_submit  name="submitpost"  value='Submit'  translate=true}   {if  $blog_post-­‐>id  gt  0} {mod_hidden  name="blog_post_id"  value=$blog_post-­‐>id} {mod_submit  name="cancelpost"  value='Cancel'  translate=true}   {/if} {mod_submit  name="submitpublish"  value='Publish'  translate=true} {/mod_form}
  71. 71. OK, let's add an admin panel ● First, we need to add a permission to control access ● This should be done in the installer ● Steps: ● Change installer ● Bump the module version number ● Create the upgrade method
  72. 72. method.install.php <?php if  (!isset($gCms))  exit; $db  =  $this-­‐>GetDb(); $dict  =  NewDataDicQonary(  $db  ); $fields=" quotaQon_id  I  KEY, language  C(8), quotaQon  X, author  C(80), submiRer  C(80), submit_date  DT "; $sqlarray  =  $dict-­‐>CreateTableSQL(  cms_db_prefix()."module_quotaQons",$fields); $dict-­‐>ExecuteSQLArray($sqlarray); $db-­‐>CreateSequence(cms_db_prefix()."module_quotaQon_seq"); $this-­‐>CreatePermission('Manage  QuotaQons',  'Manage  QuotaQons'); ?>
  73. 73. method.upgrade.php <?php if  (!isset($gCms))  exit; switch($old_version) { case  "0.1": $this-­‐>CreatePermission('Manage  QuotaQons',  'Manage  QuotaQons'); } $this-­‐>Audit(  0,  $this-­‐>Lang('friendlyname'),  $this-­‐>Lang('upgraded',$this-­‐>GetVersion())); ?> Added to lang file: $lang['upgraded']='Upgraded  to  version  %s';
  74. 74. Perform the upgrade
  75. 75. Now implement admin panel 1.x ● Add method to main module: function HasAdmin() { return ($this->CheckPermission('Manage Quotations')); }
  76. 76. action.defaultadmin.php <?php if  (!isset($gCms))  exit; if  (!$this-­‐>CheckPermission('Manage  QuotaQons'))  exit; $db=$this-­‐>GetDb(); $rows  =  array(); $res  =  $db-­‐>Execute('select  *  from  '.cms_db_prefix().'module_quotaQons  order  by  submit_date   desc'); while  ($res  &&  $row=$res-­‐>FetchRow()) { $row['edit']  =  $this-­‐>CreateLink($id,  'admin_edit',  '', $this-­‐>Lang('edit'),  array('quotaQon_id'=>$row['quotaQon_id'])); $row['delete']  =  $this-­‐>CreateLink($id,  'admin_delete',  '', $this-­‐>Lang('delete'),  array('quotaQon_id'=>$row['quotaQon_id'])); array_push($rows,$row); } $smarty-­‐>assign('quotaQons',$rows); echo  $this-­‐>ProcessTemplate('admin_display_list.tpl'); ?>
  77. 77. admin_display_list.tpl {if  isset($message)  &&  $message!=''}<div  class="pagewarning">{$message}</div>{/if} <table> {foreach  from=$quotaQons  item=q} <tr> <td>{$q.quotaQon_id}</td> <td>{$q.quotaQon|truncate:80}</td> <td>{$q.author}</td> <td>{$q.edit}</td> <td>{$q.delete}</td> </tr> {/foreach} </table>
  78. 78. Admin View
  79. 79. action.admin_delete.php <?php if  (!isset($gCms))  exit; if  (!$this-­‐>CheckPermission('Manage  QuotaQons'))  exit; if  (isset($params['quotaQon_id'])) { $db  =  $this-­‐>GetDb(); $res  =  $db-­‐>Execute('delete  from  '.cms_db_prefi x(). 'module_quotaQons  where  quotaQon_id=?', array($params['quotaQon_id'])); $smarty-­‐>assign('message',$this-­‐>Lang('quotaQ on_deleted')); } echo  $this-­‐>DoAcQon('defaultadmin',  $id,  $params,  $returnid); ?>
  80. 80. Delete Quotation
  81. 81. Be kind to users ● Add some safety – modify default admin link to delete $row['delete']  =  $this-­‐>CreateLink($id,  'admin_delete',  '', $this-­‐>Lang('delete'),  array('quotaQon_id'=>$row['quotaQon_id']), $this-­‐>Lang('really_delete',$row['author'])); ● And add to language file $lang['really_delete']='Really  delete  this  quotaQon  by  %s?';
  82. 82. That's better
  83. 83. Let admin edit quotations ● We can re-use the form template ● Just need to create the admin-side logic ● Note that the logic is not identical, since we'll be updating the database rather than adding a new record
  84. 84. action.admin_edit.php <?php if  (!isset($gCms))  exit; if  (!$this-­‐>CheckPermission('Manage  QuotaQ ons'))  exit; $db  =  $this-­‐>GetDb(); if  (isset($params['submit'])) { if  (empty($params['author'])  ||  empty($params['quotaQ on'])) { $smarty-­‐>assign('message',$this-­‐>Lang('error_empty_fi elds')); } else { $res  =  $db-­‐>Execute('update  '.cms_db_prefi x().'module_quotaQons  set  author=?,quotaQon=?  where  quotaQon_id=?', array($params['author'],$params['quotaQ on'],$params['quotaQon_id'])); if  ($res  ===  false) { $smarty-­‐>assign('message',$this-­‐>Lang('db_error',$db-­‐>ErrorMsg())); } else { $smarty-­‐>assign('message',$this-­‐>Lang('quotaQ on_edited')); } return  $this-­‐>DoAcQon('defaultadmin',  $id,  $params,  $returnid); } } else
  85. 85. action.admin_edit.php, cont { $res  =  $db-­‐>Execute('select  *  from  '.cms_db_prefi x().'module_quotaQons  where  quotaQon_id=?', array($params['quotaQon_id'])); if  ($res  &&  $row=$res-­‐>FetchRow()) { $params['author']=$row['author']; $params['quotaQon']=$row['quotaQon']; } } $smarty-­‐>assign('form_start',$this-­‐>CreateFormStart($id,  'admin_edit',  $returnid)); $smarty-­‐>assign('input_author',$this-­‐>CreateInputTextWithLabel($id,  'author', isset($params['author'])?$params['author']:'',  10,  80,  '', $this-­‐>Lang('Qtle_author'))); $smarty-­‐>assign('Qtle_quotaQon',$this-­‐>Lang('Qtle_quotaQon')); $smarty-­‐>assign('input_quotaQ on',$this-­‐>CreateTextArea(false,  $id, isset($params['quotaQon'])?html_enQty_decode($params['quotaQ on'],ENT_QUOTES):'',  'quotaQ on')); $smarty-­‐>assign('submit', $this-­‐>CreateInputHidden($id,'quotaQ on_id',$params['quotaQ on_id']). $this-­‐>CreateInputSubmit($id,  'submit',  $this-­‐>Lang('submit'))); echo  $this-­‐>ProcessTemplate('user_form.tpl'); ?>
  86. 86. Editing
  87. 87. And edited
  88. 88. action.defaultadmin.php 2.0 if  (!isset($gCms))  die("Can't  call  acQons  directly!"); if  (  !$this-­‐>Permission-­‐>check('Modify  Site  Preferences')  ) CmsResponse::redirect('index.php?'.CMS_SECURE_PARAM_NAME.'='. $_SESSION[CMS_USER_KEY]); if  (isset($params['submitprefs'])  ) { if(  !CmsAcl::check_core_permission('Modify  Site  Preferences',  $user)  ) die('permission  denied'); $password_minlength  =  (int)coalesce_key($params,'password_minlength',6); $this-­‐>Preference-­‐>set('password_minlength',$password_minlength); } $smarty-­‐>assign('groups',cms_orm('CmsGroup')-­‐>fi nd_all()); $smarty-­‐>assign('users',cms_orm('CmsUser')-­‐>fi nd_all()); $smarty-­‐>assign('acQve_tab_for_modules',    coalesce_key($params,'selected_tab','users')); $smarty-­‐>assign('form_acQon','defaultadmin'); echo  $this-­‐>Template-­‐>process('defaultadmin.tpl',$id,$return_id);
  89. 89. defaultadmin.tpl 2.0 {has_permission  perm="Modify  Templates"} <div  style="text-­‐align:  right;  width:  80%;"><a  href="listmodtemplates.php"   Qtle="{tr}modify_templates{/tr}">{tr}modify_templates{/tr}</a></div><br/> {/has_permission} {tabs} {has_permission  perm='Modify  Users'} {tab_content  name='users'} {tab_header  name='users'}{tr}users{/tr}{/tab_header} {mod_template  template='users_tab.tpl'} {/tab_content} {/has_permission} {has_permission  perm='Modify  Site  Preferences'} {tab_content  name='prefs'} {tab_header  name='prefs'}{tr}preferences{/tr}{/tab_header} {mod_template  template='prefs_tab.tpl'} {/tab_content} {/has_permission} {/tabs}

×