Building Mobile Apps in WordPress - WordCamp Toronto 2011
Upcoming SlideShare
Loading in...5
×
 

Building Mobile Apps in WordPress - WordCamp Toronto 2011

on

  • 3,198 views

Slides from my presentation, Building Mobile Apps in WordPress, at W

Slides from my presentation, Building Mobile Apps in WordPress, at W

Statistics

Views

Total Views
3,198
Views on SlideShare
2,164
Embed Views
1,034

Actions

Likes
12
Downloads
40
Comments
1

4 Embeds 1,034

http://topquark.com 1022
http://wpslide.com 9
https://twitter.com 2
https://si0.twimg.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Useful. Thanks!
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Building Mobile Apps in WordPress - WordCamp Toronto 2011 Building Mobile Apps in WordPress - WordCamp Toronto 2011 Presentation Transcript

  • Building Mobile Apps in WordPress Presenter: Trevor Mills Web: topquark.com Email: t@topquark.com Twitter: @topquarky Phone: +1(416)579-3655Tuesday, 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 RootsTuesday, 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 devicesTuesday, 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 2011Tuesday, November 8, 2011 5
  • WordPress as Mobile App WPTouch & WPTouch Pro Native App Builders WordPress Mobile Pack JAMES G. PEARCETuesday, November 8, 2011 6
  • Javascript Frameworks James Pearce Sr Director, Developer RelationsTuesday, November 8, 2011 7
  • Javascript Frameworks James Pearce Sr Director, Developer Relations David KanedaTuesday, 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 APPSTuesday, November 8, 2011 7
  • An Actual Example... THE WORDCAMP APP http://topquark.com/wordcamp/app/2011-torontoTuesday, 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-torontoTuesday, 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 SponsorsTuesday, 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); ! // dont 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 arrayTuesday, 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/asseTuesday, 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/cookiesTuesday, 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 REPOSITORYTuesday, 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 users 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-worldTuesday, 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-worldTuesday, November 8, 2011 24
  • Hello World App http://topquark.com/wordcamp/apps/hello-worldTuesday, 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-2Tuesday, November 8, 2011 25
  • Hello World App http://topquark.com/wordcamp/apps/hello-world-2Tuesday, 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/catalogueTuesday, November 8, 2011 27