Welcome to our newly overhauled Zephyr pages! See our new Overview, Examples, and Index.
Feedback is welcome at bottom of each page.


Returns a portion of a string.

substr( string input , integer start [, integer length ] )

Given a string, returns a substring of that string.

  • start is the index (starting at 0) of the string to start at.
  • length is length of the substring to return.
  • If length is not passed, the remainder of the string will be returned.


 {substr('Sailthru and Zephyr are fun', 13)}   = Zephyr are fun {substr('Sailthru and Zephyr are fun', 0, 8)} = Sailthru

Other Uses

substr() is not limited to taking a single string; you can input entire paragraphs to be returned as the substring. An example of this would be using the strip_tags() function:

{substr(strip_tags(content[0].content), x, y)}

In this example, we use strip_tags() to strip the HTML tags from the content in the data feed, returning a string. Afterwards, the substr() function returns a substring of the original string starting at integer index x, and ending at integer index y (counted in number of characters).

Remove Query Parameters from URLs in a Feed

Use Case: You have URLs in a data feed that have query string parameters appended that need to be removed in order to make use of the Sailthru auto-append parameters instead. Used in conjunction with either strrpos() or strpos().


In the Setup:

{foreach content as c}
{if contains(c.url, "?")}
{c.url = substr(c.url,0,strrpos(c.url,"?"))}


Since the first items in both the “Media” and eComm feeds have a query parameter,





This script uses a loop to check every piece of content in the feed. Within the loop, there’s a conditional “if” statement, and if a given URL contains a “?” (i.e., it has query parameter), the URL value gets reassigned. Using substr(), we take a sub-string of the URL, starting at the beginning of the string (i.e. position 0), and ending at the position before the “?”. Since the substr() functions need a numerical “end point,” using strrpos() (aka, string reverse position), we’re able to find the numerical placement of the “?”. This allows us to retrieve the necessary sub-string, which is everything from the beginning of the URL up until before the “?”.

Create a Local Variable Based on Email Address

Use Case: You want to create a local variable of each user’s email domain to pull into. You see that you can do this with a combination of subtr() and strrpos().



{domainName = substr(email,strrpos(email,"@")+1)}


<p>Hi there! What are your experiences using {domainName}?</p>


Email =

Hi there! What are your experiences using

Explanation: This script uses the subtr() function to isolate a user’s email domain for display in a template. Using substr(), we take a sub-string of the email, starting at the position after the “@”. Since the substr() functions need a numerical “end point,” strrpos() (aka, string reverse position) is used to find the numerical placement of the “@”, and using the mathematical “+” operator, add one the the value of the position. This allows us to retrieve the necessary sub-string, which is everything after the “@” sign and beyond.


Show a Countdown Clock Based On a User Variable

Use Case: You want to find out how to see how many days ago a person’s birthday was. This requires having a user’s birthday set as a var on the user profile (ex. birthay_date) in the format of YYYY-MM-DD or YYYYMMDD. Eventually, you’d like to use this to target specialized promotions (i.e. if they haven’t purchased an item since their birthday).

Used in conjunction with date(), time(), int(), strpos(), and substr(). Let’s assume the current date is January 1st.


On the User Profile:

zephyr example birthday_date

In the Setup:

{birthdayNoYear = substr(birthday_date,strpos(birthday_date,'-')+1)}
{currentYear = int(date('YYYY'))}
{currentBirthday = currentYear + '-' + birthdayNoYear}
{yearStart = time(currentYear+"-01-01")}
{birthdayTime = (time(currentBirthday) - time("now"))/86400}
{if type((currentYear+1)/4) == "float"}
{leapYear = false}
{leapYear = true}

{if date("MM-dd") == birthdayNoYear}
{birthdayCountdown = 0}

{else if birthdayTime < 1 && birthdayTime > 0}
{birthdayCountdown = 1}

{else if birthdayTime < 0 && leapYear == false}
{birthdayCountdown = int(birthdayTime) + 365}
{birthdayPass= true}

{else if birthdayTime < 0 && leapYear == true}
{birthdayCountdown = int(birthdayTime) + 366}
{birthdayPass = true}

{birthdayCountdown = int(birthdayTime) +1}

In the Code:

{if birthdayCountdown == 0}
Happy birthday!
{else if birthdayCountdown == 1}
Your birthday is tomorrow!
{else if (birthdayCountdown == 364 && leapYear == false) || (birthdayCountdown == 365 && leapYear == true)}
Your birthday was yesterday!
{else if birthdayPass == true}
Your birthday passed this year, but the next one is in {birthdayCountdown} days!
Your birthday is in {birthdayCountdown} days!


Your birthday passed this year, but the next one is in 212 days!

Show/Hide Code Explanation

This script uses substr() to take a sub-string of a custom field, in this instance, the user’s birthday (stored as “birthday_date), to retrieve the day and month of the user’s birth, leaving out the year. Since the birthday value is stored as YYYY-MM-DD, the function takes the value of that custom field, and using the strpos() function (aka string position) finds the numerical position fo the first “-” and adds one, meaning to retrieve everything after the year and dash. For example, if it were stored as “1987-08-01″, subtr() and strpos() in conjunction would return “08-01″ as the sub-string value. This value is stored as “birthdayNoYear”.

The date() function is then used to isolate the current year, and int() is used to turn in from a string to an integer, and finally the value is stored in the “currentYear” variable. A “currentBirthday” variable is created, which is the concatenation of the currentYear value plus a hypen plus the user’s birth month and day. For instance, using the same user example and if the current year is 2017, currentBirthday would equate to 2017-08-01. Next, the time() function is used to get the UNIX timestamp for the current start of the year, i.e. the value of “currentYear” plus “01-01″. The UNIX timestamp of the user’s current birthday is also needed, which is retrieved using the time() function on the “currentBirthday” value minus the UNIX timestamp of the current time, and finally dividing that value by 86400, i.e. the total number of seconds in a day. The value is stored as “birthdayTime”, and the value is the number of days left until the user’s birthday.

In order to determine if the upcoming year is a leap year, “1” is added to the current year and then divided by 4. The data type of the value is checked; if it equals “float”, the following year is not a leap year, and a variable called “leapYear” is set to “false”. Otherwise if the data type is not a float, leapYear is set to “true”. Note that leap years are wholly divisible by 4, meaning there’s no decimal place, and a “float” data type is one that contains a decimal place, so any value with a decimal was not wholly divisible, and thus not a leap year.

For the following conditional statement, int() will be used regularly to round to the nearest whole number for reader-friendliness later on. The “if” statement is used to determine if the user’s birthday is today, if it has passed for the year, or if it’s still upcoming for the year. The date() function checks to see if the current month and day is equal to the user’s “birthdayNoYear” value (their birth month and day). If so, it sets a “birthdayCountdown” variable to 0. Next it checks if checks if the value for “birthdayTime” is greater than 1 and less than 0 (which indicates that their birthday is the next day). If it is, it sets the “birthdayCountdown” variable to 1. For instance, for the example user, at 12PM on July 31st, their “birthdayTime” value would be “.5″. Setting it to 1 lets us know later on that the user’s birthday is tomorrow.

The next check is to see if their birthdayTime less than 0 (indicating that their birthday has passed this year). If it is and leapYear is false, then the “birthdayCountdown” variable is set to the value of the integer of their current “birthdayTime” (using the int() function) plus 365. A “birthdayPass” variable is also set to “true”. Next, we check the same criteria, except if “leapYear” evaluates to true, the “birthdayCountdown” variable is the value of the integer of the current “birthdayTime” (again using the int() function) plus 366. “birthdayPass” is likewise set to “true”. If none of these statements were true, then “birthdayCountdown” is set to the integer of the “birthdayTime” value plus 1. Since taking an integer rounds the value down (for example, {int(3.2)} becomes 3), adding one gives us the true number of days left until the user’s birthday.

Finally, in the code, another “if” statement evaluates the value of the “birthdayCountdown” variable. If it’s 0, indicating that there are zero days left until the user’s birthday, display a “Happy birthday!” message. If it’s 1, display a message telling the user their birthday is tomorrow. Next, if it’s not a leap year and there are 364 days left until the user’s birthday or if it is a leap year and there are 365 days left, these both indicate that the user’s birthday was yesterday, and a message saying their birthday was yesterday appears. Next, if the “birthdayPass” value evaluates to true, a message indicates as such and populates the number of days left until their next birthday. Finally, the last scenario is that their birthday hasn’t occurred yet this year. If that’s the case, a message displaying the number of days left until their birthday appears.

Converting Price (with a Decimal) from String to Number

Use Case: You have a field in a data feed you maintain with a price, but price is stored as a string and not a number. You need to do some mathematical operations, so it’s integral that the value is a number. The value has a decimal place. You’ll use map(), int(), strpos(), strrpos(), and substr() to successfully convert this value from a string to a number.


In the Setup:

{content = map(content, lambda c: c + { "newMembershipPrice": int(substr(c.vars.membership_price,0,strpos(c.vars.membership_price,"."))) + int(substr(c.vars.price,strrpos(c.vars.membership_price,".")+1))/100 })}

In the Code:

{if profile.vars.member == true}
 As a member, here are your savings on each item!
{foreach content as c}
 {if length(c.vars.membership_price) > 0}
 ${number(c.price/100 - c.newMembershipPrice,2)} on {c.title}!


As a member, here are your savings on each item!

$2.01 on To Kill a Mockingbird!

$1.84 on Salem’s Lot!

$124.25 on Women’s Leather Jacket!

$24.50 on Men’s Chelsea Boots!


This script uses the map() function to add a new parameter to a content object, in this instead a parameter called “newMembershipPrice,” which will be the numerical value of a price point currently being stored as a string. In order to determine the value for this parameter, the substr() function then takes a substring of the “membership_price” custom variable, using the strpos() function to start at the beginning of the string and finding the numerical string position of the decimal point as the endpoint. For instance, using the first item in the eComm feed as an example, “12.99” would become “12”. In order to convert this to a number, the int() function is used on that substring.

Since int() drops everything after a decimal place, the value of the cents is isolated in a similar fashion. Using substr() to isolate the value, strrpos() looks at the the same “membership_price” custom variable, finding the numerical position of the decimal point, and then adding one, isolating the “cents.” Like the first part of this script, int() is then used to convert this value to a number. In order to re-convert this number into to cents, it is the divided by 100, and going off the same example, would result in “.99″. The two numberical substrings are added together, producing “12.99”, now as a number instead of a string.

In order to leverage this new value in the Code, an “if” statement is used to check for a custom field called “member” (this can be anything of your choosing, however). If “member” equals “true”, then display the savings each user will receive as a member. Next, a foreach statement loops through each piece of content, and an “if” statement checks to see if the item has a “membership_price” field associated. If so (i.e., there’s a discounted price), the item’s price is divided by 100 as to convert it to a dollars/cents format and then the newMembershipPrice value is subtracted. The number() function is then used to convert this value to a standardized format, such as “2.01”.