Author Archive

Scaling Up with Expo for React Native Mobile Apps

Expo is a great delivery system for getting React Native mobile apps off the ground and into the hands of users. If I were to do it all over again, here is what I would have loved to know ahead of time!

Words!

Standalone App = A native app file built by Expo for iOS (ipa) or Android (apk) that is ready to upload to the respective app stores.

App Store = Either Apple’s App Store or Google Play for Android

Publish = Ah this does not mean publishing to the app stores. This means an over-the-air update. This term is accurate for Expo because your app becomes immediately available to use for users in the Expo App Client itself.

OTA = Over The Air, meaning a live update of your app content and functionality via the internets. Like serving a webpage.

Build = Means a process by which Expo uploads your code to its servers (publish) and then runs a build process in the Cloud that gives you a link to download the final product.

Your Expo Account = Your App Ecosystem

An Expo Account is *the* account that stores and serves your app. It is not a user account! Publishing your apps under this account essentially locks it to the username, and trying to switch to a different account later can cause problems. For example I identified that switching your account and republishing the same app to the same release channel will cause all the previously saved AsyncStorage user data (iOS UserDefaults) to be inaccessible.

Also if you do get into a bind of transitioning off to a new Expo account, you will end up having to annoyingly maintain apps on an old Expo login and duplicate efforts to publish your app. This is because Accounts essentially own the ecosystem which is explained later.

SecureStore vs AsyncStorage

The solution to the above problem is to use SecureStore to persist values in the user’s phone keychain. This even persists data after the user has deleted their app. SecureStore does have character limits though and I wouldn’t trust it to deal with large amounts of object data, so it should only be important key-value pairs. AsyncStorage is still important for persisting app session state, but essentially it should be treated as if the data could be wiped tomorrow.

Use Release Channels

Do it now or feel the pain later. The hierarchy of Expo is this:

  • Expo Account
    • Expo App
      • Release Channel
        • iOS/Android App

As noted above, if you ever have to switch accounts, you will end up maintaining this entire ecosystem TWICE. Your “production” release channel is different between each account!

I recommend creating new release channels for each standalone app version update too. This is because Expo often comes out with new and awesome SDK version upgrades which require a new build. The new SDK version might have code changes or features that either are not compatible or do not exist in the previous versions. A new build is also required when adding new app permissions, loading screen stuff, or tablet support.

And I won’t get into it, but you’ll see how even more complicated things get if you decide to splinter iOS and Android into separate release channels.

Just Let Expo Update the App

Expo provides an option to disable Over-the-Air updates (OTA) and provides a nice API to administer Updates yourself. This seems easy at first but can get you in trouble later.

  • Expo has had issues whereby the notification of a new Update could continue to flag even after the user has updated, creating an endless reload loop.
  • Finding a way to lock the user down to an updated version has lots of pitfalls. What if the very code to determine if the user needs to download the Update is itself broken? You have bricked their app!
  • Publish rollbacks do not resolve the above problem because you have already told Expo not to automatically update the app. It has essentially updated itself into oblivion!
  • App.json settings can not be rolled back to automatic updates because it is already integrated into the build that is live in the App Store.
  • Expo always shows its own error pages, overriding your componentDidCatch. So you couldn’t even provide an escape route or user prompt for a bricked app.

Don’t worry about it! Are updates really that big? If you’re pushing minor updates now and then the download time is minimal. And if you’re doing massive code changes, you’re better off just re-building the app for store publishing. Plus your app is basically an Expo wrapper to begin with, so you’re not really saving that much time for the convenience.

App Store Updates are Still Important

Firstly, app store updates are also meaningless. Assuming you didn’t generally tweak the app.json, you could push out app store versions 1.1, 1.2, and 1.3 and they could all read a single “production” release channel. A single publish would push to all users regardless of version. In Expo, the app.json “version” is your arbitrary versioning scheme, only “sdkVersion” is critical. Meaning it’s marketing fluff for users, much like how Google Play uses versionName vs versionCode.

I already noted some use cases by which an app store update is required. However, the magic really comes when we talk about OTA updates that fail. If an OTA update fails, meaning Expo can’t get the newest hottest thing you published, it will automatically fallback to its “bundled” state. This means Expo will serve from cache the app at the time you built it.

When disabling OTA updates and having bundled assets, you basically mimic typical native app development where each version update is a snapshot build. With OTA updates enabled, you still want an emergency cushion if Expo can’t serve the newest stuff. Under the hood, Expo will continue to try and update the user and they should see new stuff on the next app open.

Takeaways

Expo and React Native have definitely solved the problem of fast development and relative ease of delivery. However long-term maintenance and deployment of live code is still an issue. There is for example no UI by which one can easily track release channels or which users are seeing them, you really have to memorize them and provide good analytics reporting. The Expo website is a pretty basic listing of your apps and recent builds.

Overall if your team is investing in React Native over native, this is the platform to go with but do maintain robust internal tracking of your releases.

Expo build command throws errors

When working with different SDKs of Expo, switching the existing repo will cause watchman and various caches to be out of sync. Running the various clearing commands doesn’t seem to resolve it.

The build process is best done when you run a cache cleared instance with expo start -c and then in a separate window, run the build command you need.

Sending Angular $http POST Data to PHP

In the case of sending form data in Angular, $http POST data information is serialized as “application/json” which is not interpretable by PHP.

You have to transform the request (the form data object) into a format that it understands. The easiest way is to configure the $httpProvider.

/* Because PHP sucks */
myApp.config(['$httpProvider', '$httpParamSerializerProvider', function($http, $httpParamSerializerProvider) {
    var paramSerializer = $httpParamSerializerProvider.$get();
    $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
    $http.defaults.transformRequest = function(data) {
        return paramSerializer(data);
    };
}]);

 

Code Examples: CSS Squares

Back in the 2000s, creative agency websites really liked the grid effect where you would hover over a block in a grid and that block would expand into some content.  Of course then, people would use Flash or some complicated jQuery contraption.  I created my own code example of this for a client once to demonstrate a CSS3 based design working with typical HTML element flow instead of overriding everything with position absolute and calculating block sizes on the fly.   This example also serves to teach how powerful CSS inheritance can be to create series of movements that look like fancy Javascript.

It’s not a perfect example because if a user mouseovers too quickly to the next block, the widths may exceed the row and break to the next line.  A solution could be to give some extra spatial buffer to the .main-content wrapper.   jQuery is still used here to trigger the next child block to be “hidden.” Since the transitions are set the same, one smoothly replaces the other.   At the end of the row, it triggers the previous child.

Topic 1

It’s not a perfect example because if a user mouseovers too quickly to the next block, the widths may exceed the row and break to the next line.  A solution could be to give some extra spatial buffer to the .main-content wrapper.   jQuery is still used here to trigger the next child block to be “hidden.” Since the transitions are set the same, one smoothly replaces the other.   At the end of the row, it triggers the previous child.

Topic 2

It’s not a perfect example because if a user mouseovers too quickly to the next block, the widths may exceed the row and break to the next line.  A solution could be to give some extra spatial buffer to the .main-content wrapper.   jQuery is still used here to trigger the next child block to be “hidden.” Since the transitions are set the same, one smoothly replaces the other.   At the end of the row, it triggers the previous child.

It’s not a perfect example because if a user mouseovers too quickly to the next block, the widths may exceed the row and break to the next line.  A solution could be to give some extra spatial buffer to the .main-content wrapper.   jQuery is still used here to trigger the next child block to be “hidden.” Since the transitions are set the same, one smoothly replaces the other.   At the end of the row, it triggers the previous child.

Ride Sharing and the Future Urban Fabric

SF Chinatown, a place that really shouldn't have cars.

SF Chinatown, a place that really shouldn’t have cars.

I felt this TechCrunch article “Ride Sharing Will Give Us Back Our Cities” jumped the gun for me on issues of land use equity.  Planners have to be skeptical about how technology will change the landscape.  Our own foray into technology, the freeway, created an unforeseen sprawl landscape and car-centric culture.   Currently, the decoupling of home, work, and play is making it difficult to predict successful fixed-route transit.   Ride sharing as a permanent altering of transportation habits and infrastructure?  Let’s think about it.

Our cities, our cars?

The article is a bit confusing, because it advocates that residents give up their cars and then states those residents must adopt car-share.  This quandary reflects the assumptions made:

  • People still need cars, just cars that are not their own.
    • This is a highly loaded topic with geographical and racial implications.  TechCrunch’s audience, white, smart and well-to-do, needs to ditch their spoils, but then who are the ones offering their cars as tribute to the carless?  The cited studies suggest merely mode shift to other people’s cars, not giving up ownership.  It seems to me that we’re merely shifting car usage to another group of people, the rideshare chaffeurs.
  • Concentrating on helping urban residents.
    • Minneapolis I-94 during rush hour, most likely not city drivers.

      Minneapolis I-94 during rush hour, most likely not city drivers.

      Traffic is primarily an intercity (suburban to urban), not intracity problem.  Too many people in large machines wish to move between two somewhat distant locations and are funneled into one corridor.  It is not the same to state that 50,000 residents in the nearby suburb can easily give up their cars. Existing “urban” residents (likely the author means those living in pre-war city blocks) are probably not the ones causing headaches for state transportation planners.
  • Cars as intracity (neighborhood to neighborhood) problem.

    • The hidden assumption is that car-use is inherently an inner city problem, that of a driver going from the Sunset District to SOMA, or Columbia Heights to McPherson Square, or Highland Park to the U of M.  Inefficiencies are abound when city residents literally drive the route of a bus or rail line.  These people can avoid freeways, people in Menlo Park, Manassas, and Maple Grove will not.  We’ve gotten urbanites onboard rideshare, but we still have increasing number of cars on city streets.
  • The urban fabric will change.
    • The article suggests when people travel, they visit pedestrian-friendly places.  About 40 million people each visit Las Vegas and Los Angeles annually, both of which are hardly Jane Jacob’s favorite places.  New York gets 56 million.  Tourism is not a good gauge of transportation-land use policy.  Public Works departments are reinventing roads for the people they serve, not for visitors.
  • Millennials want experiences, not things.
    • This millennial is planning his awesome experience at the Northern Spark art party, but he secretly wishes he had things too.

      This millennial is planning his awesome experience at the Northern Spark art party, but he secretly wishes he had things too.

      I’m a millennial, this is not true, and the surveyors agree. Millennials would love to own their car and own their house.  They just can’t.  Things also enable experiences, like spontaneously driving your car on a road trip and not worrying about when to return it.  Millennials want detachment from responsibility, and car-share is like driving your parent’s car.  Lastly, why is this unique to millennials, shouldn’t everyone in a healthy city want great experiences in life.

City Policy vs Startup Hacking

The article does get it right in declaring the problem at hand:

Considering the inefficient use of the personal automobile, its exorbitant cost, the sheer volume of urban land devoted to serving that inefficient use and the material efficiencies achieved through ride-sharing and ride-hailing services, we just might have a chance to radically redesign our cities. If the 20th century was devoted to building the infrastructure to service the personal automobile, then perhaps the 21st century will be devoted to undoing most of it.

Fulton Street road diet.

Fulton Street road diet.

Public Works officials have already begun road diets for its “inclusive” mode design (see Fresno, CA, Louisville, KY).  It’s design is intentionally to slow vehicle traffic.  With AirBnb having defeated a major city’s ordinance, how will ride-share startups respond to future infrastructure policies (see Los Angeles’ Highland Park).

The article suggest road diets could be an outcome of ridesharing.  Arguably road diets have actually emerged from Vision Zero to eliminate pedestrian-vehicle deaths. How will rideshare companies respond when parking/stopping lanes are removed along money-making corridors, or when travel times are slowed across important thoroughfares which could affect their algorithms.  Local startup Split caters to this point of friction and curates required pick-up and drop-off locations near addresses.

Glen Park's BART streetscape redesign eliminated a coveted stopping lane in favor of an extended pedestrian waiting area.

Glen Park’s BART streetscape redesign eliminated a coveted stopping lane in favor of an extended pedestrian waiting area.

So the article speaks for a car-less future with cars.  It would be like suggest e-cigarettes (vaping) will herald the end of smoking. In actuality the future urban fabric may be fully to eliminate the car itself.   Currently, it would be more important to see rideshare’s effect upon transit, if it’s complementary or in actuality duplicative.  In 2012 TCRP wrote a 72 page report on ridesharing only to conclude:

Evidence that ridesharing complements public transit is limited, according to this examination of the state of the practice. Even though ridesharing has been around for decades as a travel mode and despite the benefits that a number of agencies have experienced a good deal of skepticism about combining ridesharing and public transit still exists.

How to Quickly Backup and Restore MAMP’s phpMyAdmin Databases

It took me some Googling to nail down the question “Where does MAMP’s phpMyAdmin (PMA) store mysql databases in OSX?” so I thought I’d summarize my findings.  The reason mysqldump isn’t as convenient is that MAMP is purposely GUI-focused, so switching brains and trying to navigate Terminal to MAMP’s mysql core is annoying and not intuitive (MAMP stores things all over the place).  Also mysqldump doesn’t easily like dumping all databases.  If we’re GUI, then let’s see if there’s a GUI solution and voila there is.

  • MAMP’s PMA stores its database files (.frm) inside HD/Library/Application Support/appsolute/MAMP PRO/db/mysql
  • Simply navigate to that folder and zip up the entire mysql folder (be wary there is also a separately named mysql folder inside this folder, ugh).
  • Throw that onto your Desktop or backup drive.
  • Let’s say you return to a fresh install of MAMP PRO, navigate back to that folder and copy all the files including ibdata1, ib_logfile1, ib_logfile0 which contains all the permissions and sql structure for phpMyAdmin.
  • Restart MAMP (which restarts mysql) and PMA should be refreshed with all your databases like nothing ever happened.

Similarly now you know how to cherry pick from old Time Machine backups instead of needing to setup the MAMP environment all over again.   Of course different versions of PMA may have changed that db folder structure, so be wary of that.

Google Maps Marker Toggle Code Example

markertoggle
As a followup to my strangely popular KML Toggle example on Google Maps, someone has prompted me to do a Marker Toggle code example.  I’m pretty late to the game to notice that Google updated some of the Maps library syntax, you can now for example pass an object literal for latitude longitude.  As a warning, the code is a bit clumped together to briefly give an example into working with markers.  I wouldn’t recommend master functions that do everything under the sun which is why Angular is a great library to separate your concerns and dependencies.

This example organizes code as follows:

  • Marker information is formatted as a json object, the standard format used today for data sharing.
  • A single global map variable.
  • The Google Map initializeMap() procedural function
    • In addition this function creates markers and your DOM controls.
  • The createMarkers() function that instantiates markers with infowindows and stores it back in the json.
  • createControls() dynamically generates the controls based on information in the json. This would be akin to using Angular’s ng-repeat.
  • toggleControl() is a state changing function that sets your checkbox state, class style, and marker visibility. It uses inverted logic, if the checkbox is checked, then do the opposite.

Click here to the Google Maps Marker Toggle code example.

// Our data source object in json format 
var markerJson = {
    "coffee1": {
        "name": "Urban Bean Coffee",
        "coordinates": {
            "lat": 44.958813,
            "lng": -93.287918
        }
    },
    "coffee2": {
        "name": "Spyhouse Coffee",
        "coordinates": {
            "lat": 44.998846,
            "lng": -93.246241
        }
    },
    "coffee3": {
        "name": "Blue Moon",
        "coordinates": {
            "lat": 44.948480,
            "lng": -93.216707
        }
    }
};

// Set a global variable for map
var map;

// Setup a listener to load the map via Google
google.maps.event.addDomListener(window, 'load', initializeMap);

/* Google Maps Related Functions */

// Initialize our goo
function initializeMap() {
    var options = {
        center: {
            lat: 44.9812,
            lng: -93.2687
        },
        zoom: 13,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }
    map = new google.maps.Map(document.getElementById("map_canvas"), options);

    // Create markers into DOM
    createMarkers(markerJson);

    // Create controls dynamically after parsing json
    createControls(markerJson);
};

// Instantiate markers in the background and pass it back to the json object
function createMarkers(markerJson) {
    for (var id in markerJson) {
        var shop = markerJson[id];
        var marker = new google.maps.Marker({
            map: map,
            position: shop.coordinates,
            title: shop.name,
            animation: google.maps.Animation.DROP
        });

        // This attaches unique infowindows to each marker
        // You could otherwise do a global infowindow var and have it overwrite itself
        marker.infowindow = new google.maps.InfoWindow({
            content: "This coffeeshop is called " + shop.name
        });

        marker.addListener('click', function() {
            this.infowindow.open(map, this);
        });

        shop.marker = marker;

    }
};

// In this example create the controls dynamically with all checked, obj is each "coffee" listing
function createControls(markerJson) {
    var html = "";
    for (var id in markerJson) {
        var shop = markerJson[id];
        html += '<li><a class="selected" href="#" id="' + id + '" onclick="toggleControl(this); return false"><input onclick="inputClick(this)" type="checkbox" checked id="' + id + '" />' + shop.name + '</a></li>';
    }
    document.getElementById("controls").innerHTML = html;
};

// Toggle class, checkbox state, and marker visibility
function toggleControl(control) {
    var checkbox = control.getElementsByTagName("input")[0];
    var shop = markerJson[control.id];
    if (checkbox.checked == true) { 
        checkbox.checked = false;
        control.className = "normal";
        shop.marker.setVisible(false); // If you have hundreds of markers use setMap(map)
    } else { 
        checkbox.checked = true;
        control.className = "selected";
        shop.marker.setVisible(true); // Similarly use setMap(null)
    }
}; 

// Cleanup function, resets controls, hides all markers, does not destroy
function removeAll() {
    for (var id in markerJson) {
        var shop = markerJson[id];
        shop.marker.setVisible(false);
        document.getElementById(id).className = "normal";
        document.getElementById(id).getElementsByTagName("input")[0].checked = false;
    }
};

// In this case we are keeping the input box for accessibility purposes, so we bubble up the click event to the parent control
function inputClick(input) {
    input.parentElement.click();
};

Full Stack Analogy for Dummies

I was discussing web programming with a bunch of urban planners only to find blank stares. To laypersons, the web is like a magical television feed that pipes into their computer screens from far away.  In reality, a web is a simple set of instructions telling your computer to create something fun and interesting.  In explaining the process of how entire technology departments create effective and maintainable websites, I had to describe the “stack” which like a layered cake allowed multiple people to seamlessly develop a website.  I stumbled in connecting each role to more relatable jobs, until recently I realized a fun analogy could be a restaurant.

The Ingredients – Code

All life began with the computer and a plethora of languages available to create the web with.  HTML is just the seasoning and plate presentation of a server-side steak dinner, which could be built of Python and php.  Sometimes these languages come pre-packaged into libraries, like pre-made sauces that help speed up the process.   Or if it’s good and you can’t tell the difference, we’ll serve you a WordPress frozen soup we’ve heated up (a content management system with our own spices). 

The Back Kitchen – Dev-Ops

Those who play with Linux servers sit in the dark back room making sure we can keep up with the booming web traffic of our hardcore ninja app.  Servers are the stoves that keep things cooking and feeding the masses.  Someone in the back has to know how to fix the deployment blender.  Purging logs like washing dishes.

The Cooks – Back-End Programmers

These people are wizards with server-side code.  They know exactly how long to prep and cook the steak.  They’ll slice zucchini the way you need it.  Server-side languages manipulate and produce the expected data, like measuring the ingredients exactly for a perfect souffle.  They execute recipes with precision so they’re not always concerned with how pretty things look once on the plate.

The Sous Chef – Front-End Programmers

In past days there were webmasters who tinkered with plain text.  Today front-end web languages like HTML, CSS, and JavaScript support the ability to have fully interactive and visually pleasurable websites.  They turn that raw server information into beautiful plate presentations that excite and challenge the eye and palate.  The back-end hands over the useful data, the grilled steak, and the front-end positions the steak on the plate, assembles the side dishes, and puts finishing touches.

The Head Chef – User Experience Designers

The head chef creates the plates and recipes everyone is busily cooking and perfecting. They set the look, the standard, the expectation.  A web designer today is designing user experience and providing visual guides to websites in addition to pixel perfect templates. Granted, a designer doesn’t necessarily drive the show come table service, they certainly set the way things will be done when they’re not there.

The House Manager and Host – CTO & Support

The chef doesn’t call all the shots, the ultimate decisions end up with the restaurant owner.  A development team is guided by a Chief Technology Officer who permeates all processes and layers.  Along with support people, they also solve client-facing problems and emergencies — the confused or disgruntled patrons.  Their steak is undercooked, there’s a hair in the soup, the waiter is rude, the web can “break” at many points in the process and so they come in to address these administrative issues.

The Wait Staff – Sales and Marketing

The business development and “growth” people will jab me in the side for calling them the wait staff.  In reality their role is very similar, they are selling the product and standing by it.  They’re delivering a promise to patrons that the menu is going to give them that great experience, for a price.  And any good salesperson will keep the client or diner happy.   These people also in turn inform and drive the development of new features or changes to the code base, like a waitress sharing dining feedback, and so are important parts in a successful code base.

So there you go, that’s a restaurant version of the web “stack.”  Each person and layer is integral to the process that creates a good website that evolves to meet its market and demand.  Now, I’m starving for food, there’s an app for that right.

jQuery Handling of CSS Classes

Though CSS3 transition animation support is still a little wonky, it’s getting better every day.  I’ve decided to pass all animation handling to CSS versus previously using jQuery’s fade functions.   jQuery is now simply the trigger, adding and removing classes.

Example: Fading Modal Box

A “modal window” is the technical term given to those annoying pop-ups in Windows.  It’s synonymous with dialog or alert.   In websites, the same concept is typically used to pop-up a larger version of a smaller image, as in a blog post.  For me, they’re useful as “page” content displays for websites which need to remain static, like in use of maps or dashboards.

jQuery

In the example below, a click listener handles the entire operation:

  • .modal-toggle is assigned to the button calling the action. ie: <a href=”#about” class=”.modal-toggle”>Click for About</a>
  • Of course, prevent default link action.
  • variable target references the href URL of the button or link. #about
  • This URL points to a div ID acting as my .modal. ie: <div id=”about”></div>
  • Next I add my “master” css class called .transitional to the .modal div.  I use a master class for applying CSS transition animations because obviously I don’t want to be adding this CSS to every single class that needs it — which increases browser load.
  • Now I’m using the link itself to judge if we’ve clicked on this before.
    • If the link has class active, then do the opposite first.  I don’t like testing negatives for if/else.
      • Remove class active, and remove class active on the modal.  Note we have to queue a delay to hide() a.k.a display: none because otherwise it won’t wait for the transition to finish. I set it to 500 ms ahead of my 400 ms.  See that hide() has a numeral hide(0) because this notifies jQuery to queue that operation; you could conceivably add more queued operations 1, 2, 3, etc.  This is required or delay does nothing.
    • If the link does not have it, let’s do our magic.
      • Add class active, then on the modal add class active.   Note we have to queue a delay on the addClass because otherwise the div will show() a.k.a. display: block immediately without waiting for the addClass.  The fancier queue function is used here because addClass cannot be queued itself.  So we have to nest it inside the available jQuery queue function.  dequeue() is required to again notify jQuery that addClass is a queued operation.   The delay is shorter, I’m just giving the browser time to separate the actions between show() and the addClass.
      • The animation is triggered by addClass(“active”) for the .modal div.
$(".modal-toggle").on("click", function(e) { 
        e.preventDefault();
	var target = $(this).attr("href");
	$(target).addClass("transitional");
	if ($(this).hasClass("active")) { 
		$(this).removeClass("active");
		$(target).removeClass("active").delay(500).hide(0);
	} else { 
		$(this).addClass("active");
		$(target).show().delay(10).queue(function(){
		    $(this).addClass("active").dequeue();
		});
	}
});

CSS

Simple enough!  The CSS is organized as follows:

  •  .modal creates our main control “layer”.  I’ve offset it from the top, assuming that’s where our main navigation link for .modal-toggle exists.  We don’t want to cover that up or we can’t close it.
  • .modal.active triggers our CSS animation to fade opacity to 100%.  That’s all it needs.
  • .content is an additional div layer nested under .modal because in general you should separate information out.  Also this lets you style the actual visible window as if it was centered on the page.
  • .transitional is my master CSS class.
.modal { 
	position: fixed;
	top: 5%;
	left: 0px;
	z-index: 1000;
	display: none;
	opacity: 0;
	width: 100%;
	height: 95%;
	}

.modal.active { 
	opacity: 1;
	}

.modal .content {
	position: relative;
	z-index: 200; 
	width: 80%; 
	height: 80%;
	margin: 0 auto 0 auto;
	background: #fff;
	padding: 20px;
	}

.transitional { 
    -webkit-transition: all 400ms ease-in;
    -moz-transition: all 400ms ease-in;
    -ms-transition: all 400ms ease-in;
    -o-transition: all 400ms ease-in;
    transition: all 400ms ease-in;
}

Get template name in WordPress

Generating the template name isn’t really a big deal, globally it’s available via echo get_option('current_page_template'). But in this case, when I was generating a slideshow of multiple pages, I needed to pass the slideshow query to it. So I had to write up my own for functions.php.


function get_template_name($query1) { 
	$template_name = get_post_meta( $query1->post->ID, '_wp_page_template', true ); 
	$length = strlen($template_name) - 4;
	if (strpos($template_name, '.php')) { 
		$template_name = substr($template_name, 0, $length);
		return $template_name;
	} else { 
		return $template_name;
	}
};

Call it after the while condition and it will generate the template name for each post (ie: echo get_template_name($query1)) The template name is stored like a simple meta value and includes the .php extension. So this will check for that to strip it out, otherwise will return ‘default.’

Why is this necessary for my slideshow? Well, some pages are to be laid out differently, this allows the CSS to make multiple slides of differing layouts.