SlideShare a Scribd company logo
1 of 37
Download to read offline
Building Mobile Apps
             in WordPress

             Presenter: Trevor Mills
             Web: topquark.com
             Email: t@topquark.com
             Twitter: @topquarky
             Phone: +1(416)579-3655
Tuesday, November 8, 2011              1
About me...

                  Studied Engineering, specializing in Quantum
                  Physics at University of Toronto

                  Programming Web Sites since 2003

                  Working with WordPress since 2010

                  Bass player in the Juno Award-Winning band
                  Digging Roots


Tuesday, November 8, 2011                                        2
Web Development in 2011

                  WordPress maturity with Version 3.x

                  15% of the top 1,000,000 sites run WordPress

                  Mobile is overtaking desktop usage

                  Mobile apps are where it’s at!




Tuesday, November 8, 2011                                        3
Web vs. Native Apps
           NATIVE APPS
                  Proprietary languages

                  Long process for App Store

                  Different versions for
                  different devices

           WEB APPS
                  Web languages - HTML, CSS &
                  Javascript

                  No app store, run from browser

                  One version for all devices

Tuesday, November 8, 2011                          4
Bridging the Phone Gap
                                             PhoneGap is an HTML5 app
                                       platform that allows you to author
                                             native applications with web
                                         technologies and get access to
                                        APIs and app stores. PhoneGap
                                             leverages web technologies
                                         developers already know best...
                                                   HTML and JavaScript.

                                   *


         * ACQUIRED BY ADOBE IN OCTOBER 2011
Tuesday, November 8, 2011                                                   5
WordPress as Mobile App
                                       WPTouch & WPTouch Pro

                                       Native App Builders

                                       WordPress Mobile Pack




                            JAMES G.
                             PEARCE


Tuesday, November 8, 2011                                      6
Javascript Frameworks
                            James
                            Pearce
                            Sr Director,
                            Developer
                            Relations




Tuesday, November 8, 2011                    7
Javascript Frameworks
                            James
                            Pearce
                            Sr Director,
                            Developer
                            Relations

                            David Kaneda




Tuesday, November 8, 2011                    7
Javascript Frameworks
                            James
                            Pearce
                            Sr Director,
                            Developer
                            Relations

                            David Kaneda
                            Creative
                            Director




            SENCHA TOUCH IS THE MOST ADVANCED JAVASCRIPT
            FRAMEWORK AVAILABLE FOR BUILDING NATIVE-FEELING,
            CROSS-DEVICE WEB APPS


Tuesday, November 8, 2011                                      7
An Actual Example...
             THE WORDCAMP APP




       http://topquark.com/wordcamp/app/2011-toronto
Tuesday, November 8, 2011                              8
An Actual Example...
             THE WORDCAMP APP
                  Data is managed in
                  WordPress

                  App is rendered by a
                  WordPress plugin

                  Runs on Sencha Touch



       http://topquark.com/wordcamp/app/2011-toronto
Tuesday, November 8, 2011                              8
Features of The
                            Conference App
                  Works offline (using HTML5 LocalStorage)

                  Includes Twitter feed and Google map

                  Allows you to favourite speakers & sessions

                  Includes Sponsors




Tuesday, November 8, 2011                                       9
How the app...
                  ...bypasses the WordPress theme

                  ...gets data from WordPress

                  ...is able to work offline



            TAKE A DEEP BREATH...
            ...LET’S GET INTO CODE!

Tuesday, November 8, 2011                           10
Bypassing WP Theme
               Use the option_rewrite_rules filter to add your own rewrite rules.
                         Note: Permalinks must be on for this to work

  add_filter('option_rewrite_rules','conf_app_rewrite_rules');
  function conf_app_rewrite_rules($rules){
  ! $p = conf_app_get_option('path');
  ! // don't allow hijacking bloginfo('url')
  ! if ($p == ''){
  ! ! return $rules;
  ! }
  !
  ! $i = 'index.php?';
  !
  ! $r[$p.'/?$'] = $i.QUERY_VAR.'=on'; // the app
  ! $r[$p.'/proposals/?$'] = $i.QUERY_VAR.'=on&'.DATA_VAR.'=proposals'; // sessions data
  ! $r[$p.'/speakers/?$'] = $i.QUERY_VAR.'=on&'.DATA_VAR.'=speakers'; // speakers data
  ! $r[$p.'/manifest/?$'] = $i.QUERY_VAR.'=on&'.MANIFEST_VAR.'=on'; // cache manifest
  ! $r[$p.'/appscript/?$'] = $i.QUERY_VAR.'=on&'.APPSCRIPT_VAR.'=on'; // app js
  !
  ! // I want the CONF_APP rules to appear at the beginning -
  ! // thereby taking precedence over other rules
  ! $rules = $r + $rules;
  !
  ! return $rules;
  }


Tuesday, November 8, 2011                                                                  11
Bypassing WP Theme
                 Use the query_vars filter to register your own valid query vars.

                 add_filter('query_vars','conf_app_query_vars');
                 function conf_app_query_vars($query_vars){
                 ! $query_vars[] = QUERY_VAR;
                 ! $query_vars[] = DATA_VAR;
                 ! $query_vars[] = MANIFEST_VAR;
                 ! $query_vars[] = APPSCRIPT_VAR;
                 ! return $query_vars;
                 }




Tuesday, November 8, 2011                                                          12
Bypassing WP Theme
                   Use the pre_get_posts action to build the pieces of your app.

  add_action( 'pre_get_posts', 'conf_app_template_redirect' );
  function conf_app_template_redirect(){
  ! if ($q = get_query_var(QUERY_VAR)) {
  ! ! // Instantiate the containers
  ! ! conf_app_load_topquark();
  ! ! global $topquark_objects;
  ! ! $tq = & $topquark_objects;
  ! !
  ! ! switch(true){
  ! ! case get_query_var(DATA_VAR) != '': $include = 'the-data/index.php'; break;
  ! ! case get_query_var(MANIFEST_VAR) != '': $include = 'the-manifest/index.php'; break;
  ! ! case get_query_var(APPSCRIPT_VAR) != '': $include = 'the-app/the-app.js.php'; break;
  ! ! default: $include = 'the-app/index.php'; break;
  ! ! }
  ! !
  ! ! include($include);
  ! ! exit();
  ! }
  }




Tuesday, November 8, 2011                                                                    13
Getting Data from WP
                            Sencha Touch requires a data MODEL (the fields)
   PHP - defining models                              PHP - Rendering Javascript
  add_filter('get_models','the_models');             $Models = apply_filters('get_models',array());
  function the_models($Models){                      foreach ($Models as $key => $model){
  ! if (is_the_conference_schedule_published()){     ! echo "Ext.regModel('$key', {n";
  ! ! $Models['Proposal'] = array();                 ! $sep = "t";
  ! ! $Models['Proposal']['fields'] = array(         ! foreach ($model as $what => $details){
  ! ! ! 'id', !! ! 'title', !! 'url',                ! ! echo $sep."$what: ";
  ! ! ! 'description','day', ! ! 'time',             ! ! echo anti_escape(json_encode($details));
  ! ! ! 'end_time', ! 'pretty_time','date',          ! ! echo "n";
  ! ! ! 'topics', ! 'room', ! ! 'proposal_type',     ! ! $sep = "t,";
  ! ! ! 'sponsor', ! 'speakers', ! 'proposals'       ! }
  ! ! );                                             ! echo "});n";
  ! }                                                }
  !
  ! if (is_the_conference_lineup_published()){
  ! ! $Models['Speaker'] = array();                  JS - Rendered Sencha Touch Javascript
  ! ! $Models['Speaker']['fields'] = array(          Ext.regModel('Proposal', {
  ! ! ! 'id', !! ! 'first_name', 'last_name',        ! fields:
  ! ! ! 'name', ! ! 'position', ! 'affiliation',     ["id","title","url","description","day","time","end_time
  ! ! ! 'bio', ! ! 'twitter', ! 'url',               ","pretty_time","date","topics","room","proposal_type","
  ! ! ! 'photo',! ! 'website', ! 'pretty_website',   sponsor","speakers","proposals"]
  ! ! ! 'proposals', 'group', ! ! 'members',         });
  ! ! ! 'hide_from_lineup'                           Ext.regModel('Speaker', {
  ! ! );                                             ! fields:
  ! }                                                ["id","first_name","last_name","name","position","affili
  !                                                  ation","bio","twitter","url","photo","website","pretty_w
  ! return apply_filters('the_models',$Models);      ebsite","proposals","group","members","hide_from_lineup"
  }                                                  ]
                                                     });




Tuesday, November 8, 2011                                                                                       14
Getting Data from WP
                            Sencha Touch requires a data STORE (the proxy)
  PHP - defining stores                                      PHP - Rendering Javascript
  add_filter('get_stores','the_stores');
  function the_stores($Stores){                             $Stores = apply_filters('get_stores',array());
  ! $app_path = conf_app_get_option('path');                foreach ($Stores as $key => $store){
  ! $u = get_bloginfo('url').'/'.$app_path.'/';             ! echo "the_conf_app.$key = new Ext.data.Store({n";
     $s = $Stores;                                          ! $sep = "t";
                                                            ! foreach ($store as $what => $details){
  !    if (is_the_conference_lineup_published()){           ! ! echo $sep."$what: ";
  !    ! $s['SpeakerStore'] = array();                      ! ! echo anti_escape(json_encode($details));
  !    ! $s['SpeakerStore']['model'] = 'Speaker';           ! ! echo "n";
  !    ! $s['SpeakerStore']['sorters'] = 'last_name';       ! ! $sep = "t,";
  !    ! $s['SpeakerStore']['getGroupString'] =             ! }
  !    ! ! do_not_escape('function(r){                      ! echo "});n";
  !    ! ! ! return r.get('last_name')[0];}');            }
  !    ! $s['SpeakerStore']['proxy'] = array(
  !    ! ! 'type' => 'scripttag','url' => $u.'speakers',
  !    ! ! 'reader' => array('type' => 'json',              JS - Rendered Sencha Touch Javascript
  !    ! ! ! ! ! ! !           'root' => 'speakers')        the_conf_app.SpeakerStore = new Ext.data.Store({
  !    ! );                                                 ! model: "Speaker"
  !    }                                                    ! ,sorters: "last_name"
  !    if (is_the_conference_schedule_published()){         ! ,getGroupString: function(r){
  !    ! $s['SessionListStore'] = array();                  ! ! return r.get('last_name')[0];}
  !    ! $s['SessionListStore']['model'] = 'Proposal';      ! ,proxy: {"type":"scripttag","url":"http://
  !    ! $s['SessionListStore']['sorters'] = 'time';        topquark.com/wordcamp/app/speakers","reader":
  !    ! $s['SessionListStore']['getGroupString'] =         {"type":"json","root":"speakers"}}
  !    ! ! do_not_escape('function(r){                      });
  !    ! ! ! return r.get('pretty_time');}');             the_conf_app.SessionListStore = new Ext.data.Store({
  !    ! $s['SessionListStore']['proxy'] = array(           ! model: "Proposal"
  !    ! ! 'type' => 'scripttag','url' => $u.'proposals',   ! ,sorters: "time"
  !    ! ! 'reader' => array('type' => 'json',              ! ,getGroupString: function(r){
  !    ! ! ! ! ! ! !           'root' => 'proposals')       ! ! return r.get('pretty_time');}
  !    ! );                                                 ! ,proxy: {"type":"scripttag","url":"http://
  !    }                                                    topquark.com/wordcamp/app/proposals","reader":
  !    return apply_filters('the_stores',$s);               {"type":"json","root":"proposals"}}
  }                                                         });

Tuesday, November 8, 2011                                                                                          15
Getting Data from WP
                                The data feed from WordPress should be JSONP
                            !   global $topquark_objects;
                            !   $tq = & $topquark_objects;
                            !
                            !   switch(get_query_var(DATA_VAR)){
                            !   case 'proposals':
                            !   ! $Shows = $tq->getPublished('Shows',$tq->year);
                            !   ! $output['proposals'] = array();
                            !   ! foreach ($Shows as $ShowID => $Show){
                            !   ! ! $show = array();
                            !   ! ! $show['id'] = intval($Show->getParameter('ShowID'));
                            !   ! ! $show['description'] = $Show->getParameter('ShowDescription');
                            !   ! ! // ... etc.
                            !   ! ! $output['proposals'][] = apply_filters('data_proposal',$show,$Show);
                            !   ! }
                            !   ! break;
                            !   case 'speakers':
                            !   ! $FestivalArtists = $tq->getPublished('FestivalArtists',$tq->year);
                            !   ! $output['speakers'] = array();
                            !   ! foreach ($FestivalArtists as $ArtistID => $Artist){
                            !   ! ! $artist = array();
                            !   ! ! $artist['id'] = intval($ArtistID);
                            !   ! ! $artist['last_name'] = $Artist['ArtistLastName'];
                            !   ! ! // ... etc.
                            !   ! ! $output['speakers'][] = apply_filters('data_speaker',$artist,$Artist);
                            !   ! }
                            !   ! break;
                            !   }

                            !   header("Content-type: text/javascript");
                            !   $c = $_GET['callback'];
                            !   echo ($c ? "$c(" : '').json_encode($output).($c ? ")" : '').';';
                            !   exit();




Tuesday, November 8, 2011                                                                                    16
Taking the App Offline
                            HTML5 provides two features to make this possible:
                                     Cache Manifest & LocalStorage




               Specify URLs to cache                         Saves Key/Value pairs

               Apps get 5MB for free                         Value can be an array




Tuesday, November 8, 2011                                                            17
Taking the App Offline
                              The Application Cache (Cache Manifest)
  DECLARING IT...                                                    RESULT...
                                                                     CACHE MANIFEST
   <html manifest="http://topquark.com/wordcamp/app/manifest">       # Version 1
                                                                     # The Main App files
                                                                     http://topquark.com/wordcamp/wp-content/plugins/the-conference
                                                                     http://topquark.com/wordcamp/wp-content/plugins/the-conference

  GENERATING IT...                                                   http://topquark.com/wordcamp/wp-content/plugins/the-conference
                                                                     http://topquark.com/wordcamp/app/2011-toronto/globals
                                                                     http://topquark.com/wordcamp/app/2011-toronto/appscript
  <?php header('Content-type: text/cache-manifest'); ?>              http://maps.google.com/maps/api/js?sensor=true
  CACHE MANIFEST
  # Version <?php echo conf_app_get_option('manifest_version'); ?>   # The App Images
                                                                     http://topquark.com/wordcamp/wp-content/plugins/the-conference
  # The Main App files                                               http://topquark.com/wordcamp/wp-content/plugins/the-conference
  # ...etc.                                                          http://topquark.com/wordcamp/wp-content/plugins/the-conference
                                                                     http://topquark.com/wordcamp/wp-content/plugins/the-conference
                                                                     http://topquark.com/wp-content/uploads/2011/06/TopQuarkLogo.pn
  # The Speaker Images
  # ...etc.                                                          # The Speaker Images
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
  <?php do_action('the_conference_app_print_manifest'); ?>           http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
  #Everything Else                                                   http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
  NETWORK:                                                           http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
  *                                                                  http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
Tuesday, November 8, 2011                                                                                                       18
                                                                     http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
Taking the App Offline
        The Application Cache (Cache Manifest) - Updating & Resetting
   UPDATING
         App Cache refreshes from server only if manifest file changes
    window.applicationCache.addEventListener('updateready',
    function(){this.swapCache(); window.location.reload();},
    false);

  RESETTING
         Chrome has chrome://appcache-internals/




Tuesday, November 8, 2011                                               19
Taking the App Offline
                                Using LocalStorage to store the data
  PHP - defining stores                                     PHP - Rendering Javascript
  add_filter('get_offline_stores','the_offline_stores');
  function the_stores($Stores){                            $Stores = apply_filters('get_offline_stores',array());
  ! $app_path = conf_app_get_option('path');               foreach ($Stores as $key => $store){
  ! $u = get_bloginfo('url').'/'.$app_path.'/';            ! echo "the_conf_app.Off$key = new Ext.data.Store({n";
     $s = $Stores;                                         ! $sep = "t";
                                                           ! foreach ($store as $what => $details){
  ! if (is_the_conference_lineup_published()){             ! ! echo $sep."$what: ";
  ! ! $s['SpeakerStore'] = array();                        ! ! echo anti_escape(json_encode($details));
  ! ! $s['SpeakerStore']['model'] = 'Speaker';             ! ! echo "n";
  ! ! $s['SpeakerStore']['sorters'] = 'last_name';         ! ! $sep = "t,";
  ! ! $s['SpeakerStore']['getGroupString'] =               ! }
  ! ! ! do_not_escape('function(r){                        ! echo "});n";
  ! ! ! ! return r.get('last_name')[0];}');              }
  ! ! $s['SpeakerStore']['proxy'] = array(
  ! ! 'type' => 'localstorage',
  ! ! 'id' => 'Speaker_'.substr(md5(get_bloginfo           JS - Rendered Sencha Touch Javascript
  ('url')),0,5)
  ! ! );                                                   the_conf_app.OffSpeakerStore = new Ext.data.OfflineStore
  ! }                                                      ({
  ! if (is_the_conference_schedule_published()){           ! model: "Speaker"
  ! ! $s['SessionListStore'] = array();                    ! ,sorters: "last_name"
  ! ! $s['SessionListStore']['model'] = 'Proposal';        ! ,getGroupString: function(r){return r.get
  ! ! $s['SessionListStore']['sorters'] = 'time';          ('last_name')[0];}
  ! ! $s['SessionListStore']['getGroupString'] =           ! ,proxy: {"type":"localstorage","id":"Speaker_8c0c2"}
  ! ! ! do_not_escape('function(r){                        });
  ! ! ! ! return r.get('pretty_time');}');               the_conf_app.OffSessionListStore = new
  ! ! $s['SessionListStore']['proxy'] = array(             Ext.data.OfflineStore({
  ! ! 'type' => 'localstorage',                            ! model: "Proposal"
  ! ! 'id' => 'Proposal_'.substr(md5(get_bloginfo          ! ,sorters: "time"
  ('url')),0,5)                                            ! ,getGroupString: function(r){return r.get
  ! ! );                                                   ('pretty_time');}
  ! }                                                      ! ,proxy: {"type":"localstorage","id":"Proposal_8c0c2"}
  ! return apply_filters('the_offline_stores',$s);         });
  }

Tuesday, November 8, 2011                                                                                             20
Taking the App Offline
                               LocalStorage - Updating & Resetting
   UPDATING
         Use timestamps to see if a store has new data
         If there is new data, load the Online Store from the server
         Then...refresh the Offline Store with the data from the Online Store
  RESETTING
         Chrome has chrome://settings/cookies




Tuesday, November 8, 2011                                                      21
Wouldn’t it
            be nice if...
                 ...there were a WordPress
              plugin to do this dirty work?




Tuesday, November 8, 2011                     22
Introducing...
                                                 BY:




                            ...NOW IN THE REPOSITORY




Tuesday, November 8, 2011                              22
The App Maker
                  Creates an Apps custom post_type

                  Build the app using shortcodes

                  Upload splash images, icon & stylesheet as
                  attachments

                  Lots of hooks to build customizations

                  No ads (unless you want to put them in)



Tuesday, November 8, 2011                                      23
Hello World App
     /**
     In the beginning, there was an app...
     And the coder declared, let there be options:

     * _is_debug_on = false (default) or true --+ sends Javascript messages to console.log()
     via a maybelog() call. Loads debug version of Sencha library.
     * _is_using_manifest = false (default) or true --+ saves data to the user's device. An
     app gets 5MB for free without having to ask the user for permission.
     * transition = slide (default), fade, pop, flip, cube, wipe (buggy) --+ the CSS3
     transition to use between pages
     * manifest_version = (string) --+ a version number for the manifest file. Useful for
     forcing new manifest load.

     ****************************************************/
     [the_app transition=cube]




   http://topquark.com/wordcamp/apps/hello-world

Tuesday, November 8, 2011                                                                      24
Hello World App
     /***************************************************
     Then the coder said,
                          let there be [ app_item ]
     may it render HTML5 markup in a variety of ways

     * _is_default = false (default) or true --+ makes this item the first one that appears.
     * title = (string) --+ the title of page. Also the title on the bottom toolbar icon.
     * icon = action, add, arrow_down, arrow_left, arrow_right, arrow_up, compose, delete,
     organize, refresh, reply, search, settings, star (default), trash, maps, locate, home
     * post = (int) --+ $post-&gt;ID of any WordPress post (optional)
     * ]]Any HTML5 markup [[ or_wordpress_shortcode ]] can be contenticized [[/ --+ create a
     page from scratch. (note: markup must pass WordPress editor valid elements)
     ***************************************************/
     [app_item title="Testing" icon=arrow_up]This is some content with <strong>markup</
     strong> and <a href="http://topquark.com">a link</a>[/app_item]
     [app_item post=1] [/app_item] +-- Note the space




   http://topquark.com/wordcamp/apps/hello-world

Tuesday, November 8, 2011                                                                      24
Hello World App




   http://topquark.com/wordcamp/apps/hello-world

Tuesday, November 8, 2011                          24
Hello World App
     /*********************************************************
     At this point, the coder paused for a smoke, whence he
     predicted someone might want to group items together to
     appear as a list, and so
                              let there be [ app_item_wrapper ]

     * title = (string) --+ the title of page. Also the title on the bottom toolbar icon.
     * icon = action, add, arrow_down, arrow_left, arrow_right, arrow_up, compose, delete,
     organize, refresh, reply, search, settings, star (default), trash, maps, locate, home
     * _is_default = false (default) or true --+ makes this item the first one that appears.
     ***************************************************/
     [app_item_wrapper title="Excellent" icon=star]
         [app_item title="Testing" icon=compose]This is some content with <strong>markup</
     strong> and <a href="http://topquark.com">a link</a>[/app_item]
         [app_item post=1] [/app_item] +-- Note the space
     [/app_item_wrapper]




   http://topquark.com/wordcamp/apps/hello-world-2

Tuesday, November 8, 2011                                                                      25
Hello World App




   http://topquark.com/wordcamp/apps/hello-world-2

Tuesday, November 8, 2011                            25
A Non-Trivial App
     [the_app]

     [app_posts post_type=records title=Discography icon=settings]

     [app_posts title="Events" _is_default=true icon=action category_name=events
     orderby=date_gmt order=asc grouped=true group_by=month indexbar=false
     list_template='<span class="title">{title}</span><span class="date secondary">
     {date:date("F jS")}</span>']




   http://patrickgrahampercussion.com/apps/my-app/

Tuesday, November 8, 2011                                                             26
A Non-Trivial App
             add_filter('the_app_post_output','patrick_app_post_output',10,2);
             function patrick_app_post_output($o,$post){
             ! if (get_query_var(APP_DATA_VAR) == 'post' and $o['_EventStartDate'] != ''){
             ! ! $o['date'] = date("M d Y",strtotime($o['_EventStartDate'][0]));
             ! ! $o['date_gmt'] = $o['_EventStartDate'][0];
                             if (strtotime($o['date_gmt']) < time()) return false;
             ! }
             ! return $o;
             }




   http://patrickgrahampercussion.com/apps/my-app/

Tuesday, November 8, 2011                                                                    26
A Non-Trivial App




   http://patrickgrahampercussion.com/apps/my-app/

Tuesday, November 8, 2011                            26
A Non-Trivial App




   http://patrickgrahampercussion.com/apps/my-app/

Tuesday, November 8, 2011                            26
Presenter: Trevor Mills
         Web: topquark.com
         Email: t@topquark.com
         Twitter: @topquarky
         Phone: +1(416)579-3655

                            http://borealisrecords.com/apps/catalogue




Tuesday, November 8, 2011                                               27

More Related Content

Similar to Building Mobile Apps in WordPress - WordCamp Toronto 2011

A Look at the Future of HTML5
A Look at the Future of HTML5A Look at the Future of HTML5
A Look at the Future of HTML5Tim Wright
 
Cross-Platform, Native Mobile Development with a DSL
Cross-Platform, Native Mobile Development with a DSLCross-Platform, Native Mobile Development with a DSL
Cross-Platform, Native Mobile Development with a DSLPeter Friese
 
Community Code: Pega Mobile
Community Code: Pega MobileCommunity Code: Pega Mobile
Community Code: Pega MobileSencha
 
Windows Phone 7.5 Mango - What's New
Windows Phone 7.5 Mango - What's NewWindows Phone 7.5 Mango - What's New
Windows Phone 7.5 Mango - What's NewSascha Corti
 
One App, Multiple Platforms
One App, Multiple PlatformsOne App, Multiple Platforms
One App, Multiple PlatformsMike Hartington
 
Brian Hogg - Web Apps using HTML5 and JS
Brian Hogg - Web Apps using HTML5 and JSBrian Hogg - Web Apps using HTML5 and JS
Brian Hogg - Web Apps using HTML5 and JS#DevTO
 
2011 The Year of Web apps
2011 The Year of Web apps2011 The Year of Web apps
2011 The Year of Web appsJungHyuk Kwon
 
Flash and Flex in an HTML5 / App Store World
Flash and Flex in an HTML5 / App Store WorldFlash and Flex in an HTML5 / App Store World
Flash and Flex in an HTML5 / App Store WorldEffectiveUI
 
PhoneGap/PhoneGap Build - Amsterdam Adobe Camp
PhoneGap/PhoneGap Build - Amsterdam Adobe CampPhoneGap/PhoneGap Build - Amsterdam Adobe Camp
PhoneGap/PhoneGap Build - Amsterdam Adobe CampMihai Corlan
 
PhoneGap Talk @ Sencha Con 2010
PhoneGap Talk @ Sencha Con 2010PhoneGap Talk @ Sencha Con 2010
PhoneGap Talk @ Sencha Con 2010alunny
 
2011 June - Singapore GTUG presentation. App Engine program update + intro to Go
2011 June - Singapore GTUG presentation. App Engine program update + intro to Go2011 June - Singapore GTUG presentation. App Engine program update + intro to Go
2011 June - Singapore GTUG presentation. App Engine program update + intro to Goikailan
 
Developing with Windows Live Spaces
Developing with Windows Live SpacesDeveloping with Windows Live Spaces
Developing with Windows Live Spacesgoodfriday
 
BlackBerry WebWorks APIs
BlackBerry WebWorks APIsBlackBerry WebWorks APIs
BlackBerry WebWorks APIsSencha
 
The NuGram approach to dynamic grammars
The NuGram approach to dynamic grammarsThe NuGram approach to dynamic grammars
The NuGram approach to dynamic grammarsNu Echo Inc.
 
Beginning Android Development
Beginning Android DevelopmentBeginning Android Development
Beginning Android DevelopmentJosé Ferreiro
 
Stream SQL eventflow visual programming for real programmers presentation
Stream SQL eventflow visual programming for real programmers presentationStream SQL eventflow visual programming for real programmers presentation
Stream SQL eventflow visual programming for real programmers presentationstreambase
 
NRWConf - Workshop Mobile Apps
NRWConf - Workshop Mobile AppsNRWConf - Workshop Mobile Apps
NRWConf - Workshop Mobile AppsPeter Hecker
 

Similar to Building Mobile Apps in WordPress - WordCamp Toronto 2011 (20)

A Look at the Future of HTML5
A Look at the Future of HTML5A Look at the Future of HTML5
A Look at the Future of HTML5
 
Groke
GrokeGroke
Groke
 
Cross-Platform, Native Mobile Development with a DSL
Cross-Platform, Native Mobile Development with a DSLCross-Platform, Native Mobile Development with a DSL
Cross-Platform, Native Mobile Development with a DSL
 
Community Code: Pega Mobile
Community Code: Pega MobileCommunity Code: Pega Mobile
Community Code: Pega Mobile
 
Windows Phone 7.5 Mango - What's New
Windows Phone 7.5 Mango - What's NewWindows Phone 7.5 Mango - What's New
Windows Phone 7.5 Mango - What's New
 
One App, Multiple Platforms
One App, Multiple PlatformsOne App, Multiple Platforms
One App, Multiple Platforms
 
ISA11 - Bill Scott - Designing Mice Men
ISA11 - Bill Scott - Designing Mice MenISA11 - Bill Scott - Designing Mice Men
ISA11 - Bill Scott - Designing Mice Men
 
Brian Hogg - Web Apps using HTML5 and JS
Brian Hogg - Web Apps using HTML5 and JSBrian Hogg - Web Apps using HTML5 and JS
Brian Hogg - Web Apps using HTML5 and JS
 
2011 The Year of Web apps
2011 The Year of Web apps2011 The Year of Web apps
2011 The Year of Web apps
 
Flash and Flex in an HTML5 / App Store World
Flash and Flex in an HTML5 / App Store WorldFlash and Flex in an HTML5 / App Store World
Flash and Flex in an HTML5 / App Store World
 
PhoneGap/PhoneGap Build - Amsterdam Adobe Camp
PhoneGap/PhoneGap Build - Amsterdam Adobe CampPhoneGap/PhoneGap Build - Amsterdam Adobe Camp
PhoneGap/PhoneGap Build - Amsterdam Adobe Camp
 
PhoneGap Talk @ Sencha Con 2010
PhoneGap Talk @ Sencha Con 2010PhoneGap Talk @ Sencha Con 2010
PhoneGap Talk @ Sencha Con 2010
 
Flutter vs React Native - Hepto.pdf
Flutter vs React Native - Hepto.pdfFlutter vs React Native - Hepto.pdf
Flutter vs React Native - Hepto.pdf
 
2011 June - Singapore GTUG presentation. App Engine program update + intro to Go
2011 June - Singapore GTUG presentation. App Engine program update + intro to Go2011 June - Singapore GTUG presentation. App Engine program update + intro to Go
2011 June - Singapore GTUG presentation. App Engine program update + intro to Go
 
Developing with Windows Live Spaces
Developing with Windows Live SpacesDeveloping with Windows Live Spaces
Developing with Windows Live Spaces
 
BlackBerry WebWorks APIs
BlackBerry WebWorks APIsBlackBerry WebWorks APIs
BlackBerry WebWorks APIs
 
The NuGram approach to dynamic grammars
The NuGram approach to dynamic grammarsThe NuGram approach to dynamic grammars
The NuGram approach to dynamic grammars
 
Beginning Android Development
Beginning Android DevelopmentBeginning Android Development
Beginning Android Development
 
Stream SQL eventflow visual programming for real programmers presentation
Stream SQL eventflow visual programming for real programmers presentationStream SQL eventflow visual programming for real programmers presentation
Stream SQL eventflow visual programming for real programmers presentation
 
NRWConf - Workshop Mobile Apps
NRWConf - Workshop Mobile AppsNRWConf - Workshop Mobile Apps
NRWConf - Workshop Mobile Apps
 

Recently uploaded

My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 

Recently uploaded (20)

My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 

Building Mobile Apps in WordPress - WordCamp Toronto 2011

  • 1. Building Mobile Apps in WordPress Presenter: Trevor Mills Web: topquark.com Email: t@topquark.com Twitter: @topquarky Phone: +1(416)579-3655 Tuesday, November 8, 2011 1
  • 2. About me... Studied Engineering, specializing in Quantum Physics at University of Toronto Programming Web Sites since 2003 Working with WordPress since 2010 Bass player in the Juno Award-Winning band Digging Roots Tuesday, November 8, 2011 2
  • 3. Web Development in 2011 WordPress maturity with Version 3.x 15% of the top 1,000,000 sites run WordPress Mobile is overtaking desktop usage Mobile apps are where it’s at! Tuesday, November 8, 2011 3
  • 4. Web vs. Native Apps NATIVE APPS Proprietary languages Long process for App Store Different versions for different devices WEB APPS Web languages - HTML, CSS & Javascript No app store, run from browser One version for all devices Tuesday, November 8, 2011 4
  • 5. Bridging the Phone Gap PhoneGap is an HTML5 app platform that allows you to author native applications with web technologies and get access to APIs and app stores. PhoneGap leverages web technologies developers already know best... HTML and JavaScript. * * ACQUIRED BY ADOBE IN OCTOBER 2011 Tuesday, November 8, 2011 5
  • 6. WordPress as Mobile App WPTouch & WPTouch Pro Native App Builders WordPress Mobile Pack JAMES G. PEARCE Tuesday, November 8, 2011 6
  • 7. Javascript Frameworks James Pearce Sr Director, Developer Relations Tuesday, November 8, 2011 7
  • 8. Javascript Frameworks James Pearce Sr Director, Developer Relations David Kaneda Tuesday, November 8, 2011 7
  • 9. Javascript Frameworks James Pearce Sr Director, Developer Relations David Kaneda Creative Director SENCHA TOUCH IS THE MOST ADVANCED JAVASCRIPT FRAMEWORK AVAILABLE FOR BUILDING NATIVE-FEELING, CROSS-DEVICE WEB APPS Tuesday, November 8, 2011 7
  • 10. An Actual Example... THE WORDCAMP APP http://topquark.com/wordcamp/app/2011-toronto Tuesday, November 8, 2011 8
  • 11. An Actual Example... THE WORDCAMP APP Data is managed in WordPress App is rendered by a WordPress plugin Runs on Sencha Touch http://topquark.com/wordcamp/app/2011-toronto Tuesday, November 8, 2011 8
  • 12. Features of The Conference App Works offline (using HTML5 LocalStorage) Includes Twitter feed and Google map Allows you to favourite speakers & sessions Includes Sponsors Tuesday, November 8, 2011 9
  • 13. How the app... ...bypasses the WordPress theme ...gets data from WordPress ...is able to work offline TAKE A DEEP BREATH... ...LET’S GET INTO CODE! Tuesday, November 8, 2011 10
  • 14. Bypassing WP Theme Use the option_rewrite_rules filter to add your own rewrite rules. Note: Permalinks must be on for this to work add_filter('option_rewrite_rules','conf_app_rewrite_rules'); function conf_app_rewrite_rules($rules){ ! $p = conf_app_get_option('path'); ! // don't allow hijacking bloginfo('url') ! if ($p == ''){ ! ! return $rules; ! } ! ! $i = 'index.php?'; ! ! $r[$p.'/?$'] = $i.QUERY_VAR.'=on'; // the app ! $r[$p.'/proposals/?$'] = $i.QUERY_VAR.'=on&'.DATA_VAR.'=proposals'; // sessions data ! $r[$p.'/speakers/?$'] = $i.QUERY_VAR.'=on&'.DATA_VAR.'=speakers'; // speakers data ! $r[$p.'/manifest/?$'] = $i.QUERY_VAR.'=on&'.MANIFEST_VAR.'=on'; // cache manifest ! $r[$p.'/appscript/?$'] = $i.QUERY_VAR.'=on&'.APPSCRIPT_VAR.'=on'; // app js ! ! // I want the CONF_APP rules to appear at the beginning - ! // thereby taking precedence over other rules ! $rules = $r + $rules; ! ! return $rules; } Tuesday, November 8, 2011 11
  • 15. Bypassing WP Theme Use the query_vars filter to register your own valid query vars. add_filter('query_vars','conf_app_query_vars'); function conf_app_query_vars($query_vars){ ! $query_vars[] = QUERY_VAR; ! $query_vars[] = DATA_VAR; ! $query_vars[] = MANIFEST_VAR; ! $query_vars[] = APPSCRIPT_VAR; ! return $query_vars; } Tuesday, November 8, 2011 12
  • 16. Bypassing WP Theme Use the pre_get_posts action to build the pieces of your app. add_action( 'pre_get_posts', 'conf_app_template_redirect' ); function conf_app_template_redirect(){ ! if ($q = get_query_var(QUERY_VAR)) { ! ! // Instantiate the containers ! ! conf_app_load_topquark(); ! ! global $topquark_objects; ! ! $tq = & $topquark_objects; ! ! ! ! switch(true){ ! ! case get_query_var(DATA_VAR) != '': $include = 'the-data/index.php'; break; ! ! case get_query_var(MANIFEST_VAR) != '': $include = 'the-manifest/index.php'; break; ! ! case get_query_var(APPSCRIPT_VAR) != '': $include = 'the-app/the-app.js.php'; break; ! ! default: $include = 'the-app/index.php'; break; ! ! } ! ! ! ! include($include); ! ! exit(); ! } } Tuesday, November 8, 2011 13
  • 17. Getting Data from WP Sencha Touch requires a data MODEL (the fields) PHP - defining models PHP - Rendering Javascript add_filter('get_models','the_models'); $Models = apply_filters('get_models',array()); function the_models($Models){ foreach ($Models as $key => $model){ ! if (is_the_conference_schedule_published()){ ! echo "Ext.regModel('$key', {n"; ! ! $Models['Proposal'] = array(); ! $sep = "t"; ! ! $Models['Proposal']['fields'] = array( ! foreach ($model as $what => $details){ ! ! ! 'id', !! ! 'title', !! 'url', ! ! echo $sep."$what: "; ! ! ! 'description','day', ! ! 'time', ! ! echo anti_escape(json_encode($details)); ! ! ! 'end_time', ! 'pretty_time','date', ! ! echo "n"; ! ! ! 'topics', ! 'room', ! ! 'proposal_type', ! ! $sep = "t,"; ! ! ! 'sponsor', ! 'speakers', ! 'proposals' ! } ! ! ); ! echo "});n"; ! } } ! ! if (is_the_conference_lineup_published()){ ! ! $Models['Speaker'] = array(); JS - Rendered Sencha Touch Javascript ! ! $Models['Speaker']['fields'] = array( Ext.regModel('Proposal', { ! ! ! 'id', !! ! 'first_name', 'last_name', ! fields: ! ! ! 'name', ! ! 'position', ! 'affiliation', ["id","title","url","description","day","time","end_time ! ! ! 'bio', ! ! 'twitter', ! 'url', ","pretty_time","date","topics","room","proposal_type"," ! ! ! 'photo',! ! 'website', ! 'pretty_website', sponsor","speakers","proposals"] ! ! ! 'proposals', 'group', ! ! 'members', }); ! ! ! 'hide_from_lineup' Ext.regModel('Speaker', { ! ! ); ! fields: ! } ["id","first_name","last_name","name","position","affili ! ation","bio","twitter","url","photo","website","pretty_w ! return apply_filters('the_models',$Models); ebsite","proposals","group","members","hide_from_lineup" } ] }); Tuesday, November 8, 2011 14
  • 18. Getting Data from WP Sencha Touch requires a data STORE (the proxy) PHP - defining stores PHP - Rendering Javascript add_filter('get_stores','the_stores'); function the_stores($Stores){ $Stores = apply_filters('get_stores',array()); ! $app_path = conf_app_get_option('path'); foreach ($Stores as $key => $store){ ! $u = get_bloginfo('url').'/'.$app_path.'/'; ! echo "the_conf_app.$key = new Ext.data.Store({n"; $s = $Stores; ! $sep = "t"; ! foreach ($store as $what => $details){ ! if (is_the_conference_lineup_published()){ ! ! echo $sep."$what: "; ! ! $s['SpeakerStore'] = array(); ! ! echo anti_escape(json_encode($details)); ! ! $s['SpeakerStore']['model'] = 'Speaker'; ! ! echo "n"; ! ! $s['SpeakerStore']['sorters'] = 'last_name'; ! ! $sep = "t,"; ! ! $s['SpeakerStore']['getGroupString'] = ! } ! ! ! do_not_escape('function(r){ ! echo "});n"; ! ! ! ! return r.get('last_name')[0];}'); } ! ! $s['SpeakerStore']['proxy'] = array( ! ! ! 'type' => 'scripttag','url' => $u.'speakers', ! ! ! 'reader' => array('type' => 'json', JS - Rendered Sencha Touch Javascript ! ! ! ! ! ! ! ! 'root' => 'speakers') the_conf_app.SpeakerStore = new Ext.data.Store({ ! ! ); ! model: "Speaker" ! } ! ,sorters: "last_name" ! if (is_the_conference_schedule_published()){ ! ,getGroupString: function(r){ ! ! $s['SessionListStore'] = array(); ! ! return r.get('last_name')[0];} ! ! $s['SessionListStore']['model'] = 'Proposal'; ! ,proxy: {"type":"scripttag","url":"http:// ! ! $s['SessionListStore']['sorters'] = 'time'; topquark.com/wordcamp/app/speakers","reader": ! ! $s['SessionListStore']['getGroupString'] = {"type":"json","root":"speakers"}} ! ! ! do_not_escape('function(r){ }); ! ! ! ! return r.get('pretty_time');}'); the_conf_app.SessionListStore = new Ext.data.Store({ ! ! $s['SessionListStore']['proxy'] = array( ! model: "Proposal" ! ! ! 'type' => 'scripttag','url' => $u.'proposals', ! ,sorters: "time" ! ! ! 'reader' => array('type' => 'json', ! ,getGroupString: function(r){ ! ! ! ! ! ! ! ! 'root' => 'proposals') ! ! return r.get('pretty_time');} ! ! ); ! ,proxy: {"type":"scripttag","url":"http:// ! } topquark.com/wordcamp/app/proposals","reader": ! return apply_filters('the_stores',$s); {"type":"json","root":"proposals"}} } }); Tuesday, November 8, 2011 15
  • 19. Getting Data from WP The data feed from WordPress should be JSONP ! global $topquark_objects; ! $tq = & $topquark_objects; ! ! switch(get_query_var(DATA_VAR)){ ! case 'proposals': ! ! $Shows = $tq->getPublished('Shows',$tq->year); ! ! $output['proposals'] = array(); ! ! foreach ($Shows as $ShowID => $Show){ ! ! ! $show = array(); ! ! ! $show['id'] = intval($Show->getParameter('ShowID')); ! ! ! $show['description'] = $Show->getParameter('ShowDescription'); ! ! ! // ... etc. ! ! ! $output['proposals'][] = apply_filters('data_proposal',$show,$Show); ! ! } ! ! break; ! case 'speakers': ! ! $FestivalArtists = $tq->getPublished('FestivalArtists',$tq->year); ! ! $output['speakers'] = array(); ! ! foreach ($FestivalArtists as $ArtistID => $Artist){ ! ! ! $artist = array(); ! ! ! $artist['id'] = intval($ArtistID); ! ! ! $artist['last_name'] = $Artist['ArtistLastName']; ! ! ! // ... etc. ! ! ! $output['speakers'][] = apply_filters('data_speaker',$artist,$Artist); ! ! } ! ! break; ! } ! header("Content-type: text/javascript"); ! $c = $_GET['callback']; ! echo ($c ? "$c(" : '').json_encode($output).($c ? ")" : '').';'; ! exit(); Tuesday, November 8, 2011 16
  • 20. Taking the App Offline HTML5 provides two features to make this possible: Cache Manifest & LocalStorage Specify URLs to cache Saves Key/Value pairs Apps get 5MB for free Value can be an array Tuesday, November 8, 2011 17
  • 21. Taking the App Offline The Application Cache (Cache Manifest) DECLARING IT... RESULT... CACHE MANIFEST <html manifest="http://topquark.com/wordcamp/app/manifest"> # Version 1 # The Main App files http://topquark.com/wordcamp/wp-content/plugins/the-conference http://topquark.com/wordcamp/wp-content/plugins/the-conference GENERATING IT... http://topquark.com/wordcamp/wp-content/plugins/the-conference http://topquark.com/wordcamp/app/2011-toronto/globals http://topquark.com/wordcamp/app/2011-toronto/appscript <?php header('Content-type: text/cache-manifest'); ?> http://maps.google.com/maps/api/js?sensor=true CACHE MANIFEST # Version <?php echo conf_app_get_option('manifest_version'); ?> # The App Images http://topquark.com/wordcamp/wp-content/plugins/the-conference # The Main App files http://topquark.com/wordcamp/wp-content/plugins/the-conference # ...etc. http://topquark.com/wordcamp/wp-content/plugins/the-conference http://topquark.com/wordcamp/wp-content/plugins/the-conference http://topquark.com/wp-content/uploads/2011/06/TopQuarkLogo.pn # The Speaker Images # ...etc. # The Speaker Images http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse <?php do_action('the_conference_app_print_manifest'); ?> http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse #Everything Else http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse NETWORK: http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse * http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse Tuesday, November 8, 2011 18 http://topquark.com/wordcamp/wp-content/blogs.dir/5/files/asse
  • 22. Taking the App Offline The Application Cache (Cache Manifest) - Updating & Resetting UPDATING App Cache refreshes from server only if manifest file changes window.applicationCache.addEventListener('updateready', function(){this.swapCache(); window.location.reload();}, false); RESETTING Chrome has chrome://appcache-internals/ Tuesday, November 8, 2011 19
  • 23. Taking the App Offline Using LocalStorage to store the data PHP - defining stores PHP - Rendering Javascript add_filter('get_offline_stores','the_offline_stores'); function the_stores($Stores){ $Stores = apply_filters('get_offline_stores',array()); ! $app_path = conf_app_get_option('path'); foreach ($Stores as $key => $store){ ! $u = get_bloginfo('url').'/'.$app_path.'/'; ! echo "the_conf_app.Off$key = new Ext.data.Store({n"; $s = $Stores; ! $sep = "t"; ! foreach ($store as $what => $details){ ! if (is_the_conference_lineup_published()){ ! ! echo $sep."$what: "; ! ! $s['SpeakerStore'] = array(); ! ! echo anti_escape(json_encode($details)); ! ! $s['SpeakerStore']['model'] = 'Speaker'; ! ! echo "n"; ! ! $s['SpeakerStore']['sorters'] = 'last_name'; ! ! $sep = "t,"; ! ! $s['SpeakerStore']['getGroupString'] = ! } ! ! ! do_not_escape('function(r){ ! echo "});n"; ! ! ! ! return r.get('last_name')[0];}'); } ! ! $s['SpeakerStore']['proxy'] = array( ! ! 'type' => 'localstorage', ! ! 'id' => 'Speaker_'.substr(md5(get_bloginfo JS - Rendered Sencha Touch Javascript ('url')),0,5) ! ! ); the_conf_app.OffSpeakerStore = new Ext.data.OfflineStore ! } ({ ! if (is_the_conference_schedule_published()){ ! model: "Speaker" ! ! $s['SessionListStore'] = array(); ! ,sorters: "last_name" ! ! $s['SessionListStore']['model'] = 'Proposal'; ! ,getGroupString: function(r){return r.get ! ! $s['SessionListStore']['sorters'] = 'time'; ('last_name')[0];} ! ! $s['SessionListStore']['getGroupString'] = ! ,proxy: {"type":"localstorage","id":"Speaker_8c0c2"} ! ! ! do_not_escape('function(r){ }); ! ! ! ! return r.get('pretty_time');}'); the_conf_app.OffSessionListStore = new ! ! $s['SessionListStore']['proxy'] = array( Ext.data.OfflineStore({ ! ! 'type' => 'localstorage', ! model: "Proposal" ! ! 'id' => 'Proposal_'.substr(md5(get_bloginfo ! ,sorters: "time" ('url')),0,5) ! ,getGroupString: function(r){return r.get ! ! ); ('pretty_time');} ! } ! ,proxy: {"type":"localstorage","id":"Proposal_8c0c2"} ! return apply_filters('the_offline_stores',$s); }); } Tuesday, November 8, 2011 20
  • 24. Taking the App Offline LocalStorage - Updating & Resetting UPDATING Use timestamps to see if a store has new data If there is new data, load the Online Store from the server Then...refresh the Offline Store with the data from the Online Store RESETTING Chrome has chrome://settings/cookies Tuesday, November 8, 2011 21
  • 25. Wouldn’t it be nice if... ...there were a WordPress plugin to do this dirty work? Tuesday, November 8, 2011 22
  • 26. Introducing... BY: ...NOW IN THE REPOSITORY Tuesday, November 8, 2011 22
  • 27. The App Maker Creates an Apps custom post_type Build the app using shortcodes Upload splash images, icon & stylesheet as attachments Lots of hooks to build customizations No ads (unless you want to put them in) Tuesday, November 8, 2011 23
  • 28. Hello World App /** In the beginning, there was an app... And the coder declared, let there be options: * _is_debug_on = false (default) or true --+ sends Javascript messages to console.log() via a maybelog() call. Loads debug version of Sencha library. * _is_using_manifest = false (default) or true --+ saves data to the user's device. An app gets 5MB for free without having to ask the user for permission. * transition = slide (default), fade, pop, flip, cube, wipe (buggy) --+ the CSS3 transition to use between pages * manifest_version = (string) --+ a version number for the manifest file. Useful for forcing new manifest load. ****************************************************/ [the_app transition=cube] http://topquark.com/wordcamp/apps/hello-world Tuesday, November 8, 2011 24
  • 29. Hello World App /*************************************************** Then the coder said, let there be [ app_item ] may it render HTML5 markup in a variety of ways * _is_default = false (default) or true --+ makes this item the first one that appears. * title = (string) --+ the title of page. Also the title on the bottom toolbar icon. * icon = action, add, arrow_down, arrow_left, arrow_right, arrow_up, compose, delete, organize, refresh, reply, search, settings, star (default), trash, maps, locate, home * post = (int) --+ $post-&gt;ID of any WordPress post (optional) * ]]Any HTML5 markup [[ or_wordpress_shortcode ]] can be contenticized [[/ --+ create a page from scratch. (note: markup must pass WordPress editor valid elements) ***************************************************/ [app_item title="Testing" icon=arrow_up]This is some content with <strong>markup</ strong> and <a href="http://topquark.com">a link</a>[/app_item] [app_item post=1] [/app_item] +-- Note the space http://topquark.com/wordcamp/apps/hello-world Tuesday, November 8, 2011 24
  • 30. Hello World App http://topquark.com/wordcamp/apps/hello-world Tuesday, November 8, 2011 24
  • 31. Hello World App /********************************************************* At this point, the coder paused for a smoke, whence he predicted someone might want to group items together to appear as a list, and so let there be [ app_item_wrapper ] * title = (string) --+ the title of page. Also the title on the bottom toolbar icon. * icon = action, add, arrow_down, arrow_left, arrow_right, arrow_up, compose, delete, organize, refresh, reply, search, settings, star (default), trash, maps, locate, home * _is_default = false (default) or true --+ makes this item the first one that appears. ***************************************************/ [app_item_wrapper title="Excellent" icon=star] [app_item title="Testing" icon=compose]This is some content with <strong>markup</ strong> and <a href="http://topquark.com">a link</a>[/app_item] [app_item post=1] [/app_item] +-- Note the space [/app_item_wrapper] http://topquark.com/wordcamp/apps/hello-world-2 Tuesday, November 8, 2011 25
  • 32. Hello World App http://topquark.com/wordcamp/apps/hello-world-2 Tuesday, November 8, 2011 25
  • 33. A Non-Trivial App [the_app] [app_posts post_type=records title=Discography icon=settings] [app_posts title="Events" _is_default=true icon=action category_name=events orderby=date_gmt order=asc grouped=true group_by=month indexbar=false list_template='<span class="title">{title}</span><span class="date secondary"> {date:date("F jS")}</span>'] http://patrickgrahampercussion.com/apps/my-app/ Tuesday, November 8, 2011 26
  • 34. A Non-Trivial App add_filter('the_app_post_output','patrick_app_post_output',10,2); function patrick_app_post_output($o,$post){ ! if (get_query_var(APP_DATA_VAR) == 'post' and $o['_EventStartDate'] != ''){ ! ! $o['date'] = date("M d Y",strtotime($o['_EventStartDate'][0])); ! ! $o['date_gmt'] = $o['_EventStartDate'][0]; if (strtotime($o['date_gmt']) < time()) return false; ! } ! return $o; } http://patrickgrahampercussion.com/apps/my-app/ Tuesday, November 8, 2011 26
  • 35. A Non-Trivial App http://patrickgrahampercussion.com/apps/my-app/ Tuesday, November 8, 2011 26
  • 36. A Non-Trivial App http://patrickgrahampercussion.com/apps/my-app/ Tuesday, November 8, 2011 26
  • 37. Presenter: Trevor Mills Web: topquark.com Email: t@topquark.com Twitter: @topquarky Phone: +1(416)579-3655 http://borealisrecords.com/apps/catalogue Tuesday, November 8, 2011 27