WordPress Post Revisions: Go back in time!

WordPress saves revisions of your posts as you edit. This may not be obvious to you. With a post open for editing, click the “Screen Options” dropdown in the upper right of your screen and check the box for “Revisions”. If you don’t see it, you are probably looking at a post with no revisions. Once on, it is a sticky setting so you should always see the revisions section at the bottom of the page when editing posts.

To go back to a prior revision, click the link next to the revision you want, compare the revision to the current version and click the “Restore This Revision” button if you really want to go back to the revision.

This can be a lifesaver if you’ve broken some complex HTML or lost some important content inadvertently!

Pocono Heritage Land Trust

Image of PHLT website

Pocono Heritage Land Trust (PHLT) contacted Trail Websites after hearing about us at the Pennsylvania Land Trust Association Land Conference this spring. PHLT was in need of an improved website that was mobile responsive, easier to manage and with event management and ticket selling capabilities.

The new PHLT website launchd in July 2017 and is the foundation on which they will be able to add more content to share with their community. Event management with the ability to pre-register and sell tickets is a function of the site that met their specific requirements. The site also offers improvements to the online giving experience, making it more likely that donors will complete the process.

We welcome PHLT to the Trail Websites customer community and congratulate them on their new website. Executive Director Cindy Miano was able to rapidly work with us to establish requirements and provided us content and feedback in a very timely manner. With her help, we were able to complete and launch the new PHLT website in just a few weeks.

New River Land Trust

image of home page of NRLT's new website
New River Land Trust’s new website
New River Land Trust (NRLT) found Trail Websites via social media. They wanted to improve their website to make it easier to maintain and navigate as well as improving support for devices with small screens and touch interfaces like smartphones and tablets.

As with many of Trail Websites’ customers, NRLT had great content about their conservation work, properties, organization and programs. They just needed some help presenting it in an up-to-date way and a better way to make changes in the future.

The staff as NRLT put a great deal of thought and effort into evaluating their current content, documenting needed updates and gathering media to support the words with imagery, downloadable assets and graphics.

The end result looks great and presents NRLT to the community in a professional, organized way that helps people appreciate the mission and work. Visit the site to see what we created together!

Tools for checking your website

Trail Websites recommends using a security plugin like Wordfence or Sucuri to protect your WordPress based website. Both companies now offer free site scanners you can use to quickly check whether your website has any glaring security risks. Before I give you the links, a few notes:

  1. No single tool can tell you if your site is 100 percent safe. Keep software updated, do regular backups, use strong passwords and do all the other reasonable things that make a website safe.
  2. These are valuable tools but they are also sales tools. Keep that in mind when reading the results. Whether they find any issues or not, there will be at least a subtle push to add their security plugin to your site. We encourage you to consider doing exactly that because it is a good safety practice, not because they say so in the free test results.

Wordfence just launched They will ask you to sign up for a free account to get expanded results and so they can market to you by email. This tool just launched and demand is high so it could take a few minutes for your request to make it through the queue for scanning. Be patient, the results are worth the wait if they help you find and address weaknesses. Wordfence seems to want Gravityscan to exist as a free service with its own brand. They don’t hide the relationship. They do sell a scheduled scan for $10 / month as a “Pro” version of the service so you don’t need to keep remembering to run the scan yourself. Our recommendation: install Wordfence on your site. Even the free version does a more complete scan, more often, and sends you instant alerts for problems along with periodic reports. Wordfence focuses exclusively on WordPress though Gravityscan will provide useful reports for sites running on other solutions.

Sucuri has been operating for a while now. They do not ask you to sign up for an account but they do surround the test experience with more advertising for their products and services and, unlike Wordfence’s Gravityscan, make no attempt to position the tool as separate from their brand. Sucuri is a little more expensive than Wordfence and they no longer offer a free product. Sucuri is especially useful if you use a range of platforms and want one security tool since they support WordPress, Drupal, Magento, Joomla, Microsoft ASP.NET, phpBB and Bulletin.

Need help securing your WordPress website and keeping it secure? Consider having Trail Websites manage your website for you.

Stewardship Reporting with Google Forms

Land trusts practicing good land stewardship produce a report each year summarizing stewardship activity and land use for stewarded properties. We’ve seen many methods for gathering data from stewards and producing the final report. Some assemble physical copies of handwritten reports into a binder. Others type up reports in a word processor. Some have built elaborate, form based tools of their own. We helped Littleton Conservation Trust leverage Google Forms to gather the input and used some Google Apps scripting to generate the report as a Google document that could then be edited to add a cover letter and insert any other information.

The Form
Here are the fields we placed on the form:

Property Name – a text field for the property name, could be a dropdown list for better consistency

Steward(s) (Visits per steward) – name(s) followed by number of visit in parentheses such as “Sam Steward (17)”

Total Steward Visits – total # of visits by all stewards for this property

Date of this Report – date field for date this report was filled out

Report Prepared By – who filled out the report

Conditions – grid field with Good, Average, Poor, Not Applicable columns and Signs / Gates, Entrance, Parking, Trails, Boundary Markers, Waterways, Roads, Vandalism/Littering rows.

Other – text field for a custom condition

Other Rating – radio buttons field with Good, Average and Poor (1,2,3)

Public Tours – text field for info on public tours of the land

Land Usage – more general field to describe how the land is used

Brochure/Maps – do brochures and maps need updating or refilling at kiosks?

Projects / Maintenance Completed – long text field

Projects / Maintenance In Progress – long text field

Projects / Maintenance To Be Done – long text field

Additional Remarks – long text field

Collecting Responses
We set the form’s sharing to “Anyone who has the link”. If you have a license for Google G-Suite (paid or through the nonprofit program), you can share with your domain only but that only works if the stewards all have Google Accounts in your domain.

We emailed the stewards the link with the request and instructions for filling out the form. With wide ranging computer skills and habits from years of reporting, we gave them the option of filling out a paper form and sending it in if they’d rather we did the data entry to the form. All but one filled out the online form so there was very little re-entry.

The Script
Next we created a script to process the form responses. We’re working on the best way to package the script and activate it from a nice user interface. For now, it just lives in a document and we run it manually from the script editor.

This script is specific to our form and our reporting format so use it as a starting point but plan to edit it to fit your needs.

Create a new, blank Doc in Google Docs. Type a basic description into the document body and name the document so you know what it holds! Otherwise you may accidentally erase it in the future when you see what looks like an empty document. We named ours “Stewardship Report Script” and wrote “This document holds the script for generating the annual stewardship report from form responses.” in the body.

From the Tools menu, choose Script Editor. Remove the default script template from the editor and replace it with the following:

// Script for generating steward reports from Google Form Responses
// Version 1.0
// 2017-03-26 by Scott Lewis

// styling for the title
var title = {};
  title[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER;
  title[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
  title[DocumentApp.Attribute.FONT_SIZE] = 24;
  title[DocumentApp.Attribute.BOLD] = true;

//styling for normal text
  var normal = {};
  normal[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
  normal[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
  normal[DocumentApp.Attribute.FONT_SIZE] = 11;
  normal[DocumentApp.Attribute.BOLD] = false;

// styling for headings
  var heading = {};
  heading[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
  heading[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
  heading[DocumentApp.Attribute.FONT_SIZE] = 16;
  heading[DocumentApp.Attribute.BOLD] = true;

// styling for bold, normal text
  var bold = {};
  bold[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.LEFT;
  bold[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
  bold[DocumentApp.Attribute.FONT_SIZE] = 11;
  bold[DocumentApp.Attribute.BOLD] = true;

// styling for the conditions table
  var checkStyle = {};
  checkStyle[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
  checkStyle[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.CENTER;
  checkStyle[DocumentApp.Attribute.FONT_SIZE] = 14;

// add a row to the conditions table. t = table object, l = label text, c = condition.
function addRow(t, l, c) {
  var r = t.appendTableRow();
  var lc = r.appendTableCell(l);
  if (c == "Good") {
    var cellg = r.appendTableCell("✔︎");
  } else {
    if (c == "Average") {
      var cella = r.appendTableCell("✔︎");
    } else {
      if (c == "Poor") {
      var cellp = r.appendTableCell("✔︎");
      } else {
        var celln = r.appendTableCell("✔︎");

// add a paragraph. b = document body, l = label (added in bold), c = contents (added in normal), ns = newline after label, ne = newline after paragraph body.
function addP(b, l, c, ns, ne) {
  if (c > "") {
    var p = b.appendParagraph("TEMP");
    var lbl = p.appendText(l);
    if (ns == true) { p.appendText("\r"); }
    var content = p.appendText(c);
    if (ne == true) { p.appendText(" \r"); }

// main function to generate report
function generateReport() {
  var d = new Date();
  var reportYear = d.getFullYear()-1;
// a new Doc will be created each time this script runs. Remember to delete old ones if you are testing changes.
// create the new file and name it with the year appended to the name
  var reportDoc = DocumentApp.create('Annual Land Stewardship Reports for ' + reportYear);
  var reportBody = reportDoc.getBody();
  // add title page content
  var reportTitle = reportBody.appendParagraph("\r\r\r\r\rAnnual Land Stewardship Reports for " + reportYear + "\r\r\r\r\r\r\r");
  var dateStr = d.getMonth()+"/"+d.getDate()+"/"+d.getFullYear();
// customize the credits to your organization's specifics
  var reportCredits = reportBody.appendParagraph("Prepared and submitted "+dateStr+" by Stewardship Coordinator and Land Stewards.");
//new page after title page is done
// get the form The Id is specific to your form. You can see it in the URL at the top of the page when viewing the form in Google Forms. The first time your script accesses your form, you'll need to give it permission in the popup that appears.
  var form = FormApp.openById('usdlfisfe4r346856fdfdg');  // random Id for this example, not an actual form Id
  var formResponses = form.getResponses();
// loop through the form responses
  for (var i = 0; i < formResponses.length; i++) {
    var formResponse = formResponses[i];
    var itemResponses = formResponse.getItemResponses();
// name this page with the property name
    var pName = reportBody.appendParagraph(itemResponses[0].getResponse()+"\r");
// add who filed the report, which stewards visited the property and number of visits per steward and in total
    var reportedDate = itemResponses[3].getResponse();
    addP(reportBody, "Reported by: ", itemResponses[4].getResponse() + " on " + reportedDate, false, false);
    addP(reportBody, "Steward(visits): ", itemResponses[1].getResponse(), false, false);
    addP(reportBody, "Total Visits: ", itemResponses[2].getResponse(), false, true);
// new paragraph for conditions
    var rB = reportBody.appendParagraph("Conditions:");
// table of conditions
    var lOther = itemResponses[6].getResponse();
    var aC = itemResponses[5].getResponse();
    var tConditions = reportBody.appendTable();
    var rH = tConditions.appendTableRow();
    addRow(tConditions, "Signs / Gates", aC[0]);
    addRow(tConditions, "Entrance", aC[1]);
    addRow(tConditions, "Parking", aC[2]);
    addRow(tConditions, "Trails", aC[3]);
    addRow(tConditions, "Boundary Markers", aC[4]);
    addRow(tConditions, "Waterways", aC[5]);
    addRow(tConditions, "Roads", aC[6]);
    addRow(tConditions, "Litter / Vandalism", aC[7]);
// now add the rest of the fields
    addP(reportBody, "Brochures: ", itemResponses[9].getResponse(), true, true);
    addP(reportBody, "Public Tours: ", itemResponses[7].getResponse(), true, true);
    addP(reportBody, "Land Usage: ", itemResponses[8].getResponse(), true, true);
    addP(reportBody, "Completed Projects: ", itemResponses[10].getResponse(), true, true);
    addP(reportBody, "In-Progress Projects: ", itemResponses[11].getResponse(), true, true);
    addP(reportBody, "Future / Needed Projects: ", itemResponses[12].getResponse(), true, true);
    addP(reportBody, "Remarks: ", itemResponses[13].getResponse(), true, false);
// new page to get ready for next property

What is happening in this script?

Each formResponse is a steward's report for a property. We start with the property name as a heading then add the steward'(s) name / number of visits per steward and the total number of visits. This information comes from the first few itemResponses in each formResponse.

Then we create a table and add the itemResponse data from the grid for conditions. We could have retrieved the labels for the rows from the grid itself but we wanted to shorten some names for better fit on the page so we manually typed the labels into the script. We add a row to the table for each condition and our addRow functions places the checkmark in the correct column based on the condition from the form.

Now we add the rest of the fields and the general remarks as additional paragraphs and start a new page to be ready for the next formResponse.

Each time this script runs, it generates a Google Doc named "Annual Land Stewardship Report for yyyy" where yyyy = the year before the current year as reports are typically prepared early in the new year for the prior year. If you run this script repeatedly while modifying it to your needs, you'll end up with a lot of documents all with the same name so delete the unneeded ones as you go to keep things simple.

After you generate the report, you can open it in Google Docs and edit it as needed. Add a cover letter, illustrate issues or progress with graphics or photos, generate a table of contents from the headings or add page numbering and headers and footers.

How do you run the script?
In the script editor, choose your function (generateReport in our example) where it says "Selection function" then press the Play icon.

What's Next?
As mentioned, we will be making this more end-user friendly by moving the script into a form or other element where it can be initiated from clicking a button.

Other improvements we're exploring include using Google's file upload ability in the form so that stewards can upload photos to illustrate issues needing attention or to show the results of projects. We may also add a cover letter generator so that the process is managed by a form that asks a few questions of the stewardship coordinator then presents a button that generates the report including a cover letter generated from his or her answers.

2017 Trail Websites Update

Here’s a video we’re working on for spring conferences that gives a pretty good overview of our current capabilities and how they’ve been applied to several customers’ websites. Of special interest this year is the enhanced online donation form capabilities we added.

First, be genuine

It is tempting to get lost in the maze of Search Engine Optimization, working hard on catchy headlines and keyword filled content, trying to learn the latest in the SEO algorithm race to game the search engines into bringing you more traffic. And you should pay attention to generating traffic. With limited time and budget, should you spend your resources on SEO or the real content of your message?

At Trail Websites, we have found that a genuine, impactful message does more for our customers’ missions than extra time and money focused on search optimization, flashy graphics, animations and other shiny objects. Yes, you need to bring people to your content and keep their attention there long enough for them to hear your message. But the message does the work. Keywords, animated GIFs and views by people who aren’t interested in your cause won’t help your fundraising or community engagement on their own.

After a few years of focusing on data, one of our nonprofit customers, a food pantry, shifted their focus to the stories of their clients in 2016. They had their best annual appeal ever and their year-end appeal appears to also be on track to break records. They still used data to support the stories and show that the story of one is the story of many. They spent more time on the genuine impact of the problem and what they do to help though and, along with an improving economy, translated to increased donations. Feeling like the stories were about their own neighbors drove more giving than infographics full of stats on hunger.

A land trust focused on getting people outdoors and having group leaders tell the story of the land’s history and its future potential — one path leading to habitat, drinking water safety, public recreation and non-motorized commuter access to the rail station and the other path leading to houses, increased demand for public services and higher taxes — with a result of voter turnout at town meeting in support of acquiring the property for open space. Local interest drew people in far more than today’s hot keywords like climate change, environmental impact, sprawl and endangered species.

There are two takeaways in these examples:

  • Data is a supporting piece of the story, not the story.
  • Know your audience. If the audience is local and the impact is local, the story needs to be local.

One other aspect of both of these examples is important to note: In both cases, similar stories and images were consistently used across press, website, email campaigns, newsletters and handouts. In today’s short attention span, soundbite and tweet filled world, frequency and repetition matter more than ever.

The Walden Woods Project

image of the home page of the new website
The Walden Wood Project’s new website.

We launched The Walden Woods Project’s new website today. Their prior site had a nice historical feel and a lot of useful content. It was showing its age though with a dependency on Flash for the home page, search tools that weren’t working and no friendliness for mobile devices.

The new site balances a more modern look with historic elements. It adds a sophisticated system for managing and presenting the many works in their collection of content by, and about, Henry David Thoreau. It works on mobile devices, has useful search facilities and much easier tools for donations and their online store.

The site features beautiful imagery from Walden Pond and the surrounding area and a video introduction by Don Henley, founder of The Eagles and The Walden Woods Project.

The Walden Woods Staff put many hours of work into updating, refining, organizing and creating content for this new site. Our part was creating the home and tools for experiencing their content. Visit the site to see what we created together!

Make your event calendar more effective

calendar_300_300If you are like most trusts and other nonprofits, you publish some form of calendar or event listing on your website. You probably even promote it through your newsletter and social media channels. But it isn’t getting the traffic it should. It may be a case of going where your audience is being a better option than trying to bring them to where you are over and over again.

At Trail Websites, we rely on Events Manager to build event management into our customers’ websites. We like that it allows us the freedom to style the event lists as needed and that it has built-in event registration and even ticket selling abilities when we need them. It also has a less often promoted ability to share its contents through the Internet Calendar protocol also known as iCal.

If your calendar is accessible by iCal, consider promoting the idea of subscribing to your calendar instead of trying to get people to go check your calendar periodically. That way your events will show up as a calendar in their calendar software on their phone, tablet or computer — the place(s) they check their daily schedule all the time!

Here’s an example of instructions that can be shared with your audience on how to subscribe to an iCal calendar:

To subscribe to our calendar using iCal, use this URL: (replace with your real domain and /events.ics with your calendar solution’s ical endpoint)

This will subscribe to the monthly meetings and special events only. We exclude the outside events as there can be many of them on the same day (especially spring plant sales) and we don’t want to fill up your calendar with all of them. (This wording is specific to the calendars of a client’s website. Modify it to suit your approach to calendaring.)

In Apple Mail, choose File | New Calendar Subscription, then paste the above URL into the Calendar URL field and press the Subscribe button. Name it whatever you like then press OK to save it (change the other settings, if you need to, first).

In Google Calendar, click the little down arrow next to “Other Calendars” on the lower left of the screen then choose “Add by URL” and paste the above URL into the URL field and press Add Calendar. Generally you won’t want to check the “Make the calendar publicly accessible box”. It is better to refer people to this page and have them subscribe to the source so they get reliable updates when we change the calendar.