Search

I’m trying to build a single Dynamic XML data source that pulls Twitter feeds for each of a group of 30+ users. I have a page that displays personalized information for each person with a single URL parameter: $team-member.

The $team-member URL parameter does not match the Twitter user/screen_name. So, I can’t use this parameter to be able to dynamically modify the URL parameter of the dynamic data source. So this won’t work:

http://twitter.com/statuses/user_timeline/{$team-member}.xml

So far, the only solution that works is to create a data source for each team member and modify each data source, similar to what Nils suggested to prevent all data sources firing when I only need the Twitter data for each individual.

<?php

    require_once(TOOLKIT . '/class.datasource.php');

    Class datasourcetwitter_screenname extends Datasource{

        public $dsParamROOTELEMENT = 'twitter-screenname';
        public $dsParamURL = 'http://twitter.com/statuses/user_timeline/screenname.xml';
        public $dsParamXPATH = '/statuses/status[position() &lt; 3]';
        public $dsParamCACHE = '30';
        public $dsParamTIMEOUT = '6';
        public function __construct(&$parent, $env=NULL, $process_params=true){
            parent::__construct($parent, $env, $process_params);
            $this->_dependencies = array();
        }

        public function about(){
            return array(
                     'name' => 'Twitter: screenname',
                     'author' => array(
                            'name' => 'Stephen Bau',
                            'website' => 'http://example.com',
                            'email' => 'stephen@domain7.com'),
                     'version' => '1.0',
                     'release-date' => '2010-05-08T02:15:16+00:00');    
        }

        public function getSource(){
            return 'dynamic_xml';
        }

        public function allowEditorToParse(){
            return false;
        }

        public function grab(&$param_pool=NULL){
            $result = new XMLElement($this->dsParamROOTELEMENT);

            if($this->_env['env']['url']['team-member'] != 'screenname') return $this->emptyXMLSet();

            try{
                include(TOOLKIT . '/data-sources/datasource.dynamic_xml.php');
            }
            catch(FrontendPageNotFoundException $e){
                // Work around. This ensures the 404 page is displayed and
                // is not picked up by the default catch() statement below
                FrontendPageNotFoundExceptionHandler::render($e);
            }           
            catch(Exception $e){
                $result->appendChild(new XMLElement('error', $e->getMessage()));
                return $result;
            }   

            if($this->_force_empty_result) $result = $this->emptyXMLSet();
            return $result;
        }
    }

What I’d really like to figure out is how to match the $team-member parameter to the Team section’s twitter field containing the twitter screen name using a single data source, rather than creating a data source for each team member.

I was thinking about using an array of key => value pairs in a custom data source to dynamically set the screen name based on the value of the $team-member URL parameter:

$teamMember = $this->_env['env']['url']['team-member'];
$twitterAccounts = array(
    'john-smith'     => 'jsmith',
    'jane-doe'       => 'jdoe',
    'bob-loblaw'     => 'blahblahblah',
    'stephen-bau'    => 'bauhouse',
);
$twitterUsername = $twitterAccounts[$teamMember];

$dsParamURL = 'http://twitter.com/statuses/user_timeline/' . $twitterUsername . '.xml';

But I don’t know how to make something like this work.

I tried hacking the data source constructor method, which is probably very bad practice, just to see if I could get this to work. (You might notice that I’m a PHP novice.)

<?php

    require_once(TOOLKIT . '/class.datasource.php');

    Class datasourcetwitter_team extends Datasource{

        public $dsParamROOTELEMENT = 'twitter-team';
        public $dsParamURL;
        public $dsParamXPATH = '/statuses/status[position() &lt; 3]';
        public $dsParamCACHE = '30';
        public $dsParamTIMEOUT = '6';

        public $teamMember;
        public $twitterUsername;

        public function __construct(&$parent, $env=NULL, $process_params=true){

            $teamMember = $this->_env['env']['url']['team-member'];
            $twitterAccounts = array(
                'john-smith'     => 'jsmith',
                'jane-doe'       => 'jdoe',
                'bob-loblaw'     => 'blahblahblah',
                'stephen-bau'    => 'bauhouse'
            );
            $twitterUsername = $twitterAccounts[$teamMember];

            $dsParamURL = 'http://twitter.com/statuses/user_timeline/' . $twitterUsername . '.xml';

            parent::__construct($parent, $env, $process_params);
            $this->_dependencies = array();
        }

        public function about(){
            return array(
                     'name' => 'Twitter: Team',
                     'author' => array(
                            'name' => 'Stephen Bau',
                            'website' => 'http://home/domain7/site',
                            'email' => 'stephen@domain7.com'),
                     'version' => '1.0',
                     'release-date' => '2010-05-09T20:24:00+00:00');    
        }

        public function getSource(){
            return 'dynamic_xml';
        }

        public function allowEditorToParse(){
            return false;
        }

        public function grab(&$param_pool=NULL){
            $result = new XMLElement($this->dsParamROOTELEMENT);

            if(empty($twitterUsername)) return $this->emptyXMLSet();

            try{
                include(TOOLKIT . '/data-sources/datasource.dynamic_xml.php');
            }
            catch(FrontendPageNotFoundException $e){
                // Work around. This ensures the 404 page is displayed and
                // is not picked up by the default catch() statement below
                FrontendPageNotFoundExceptionHandler::render($e);
            }           
            catch(Exception $e){
                $result->appendChild(new XMLElement('error', $e->getMessage()));
                return $result;
            }   

            if($this->_force_empty_result) $result = $this->emptyXMLSet();
            return $result;
        }
    }

But that doesn’t work. What would be the best way to go about this?

Just change $dsParamURL to $this->dsParamURL in the constructor, underneath where you have the username mapping array.

Then you’ll be correctly filling the value of the object member dsParamURL, rather than filling the value of a same-named variable local only to that function.

I’ll be needing to do something exactly like this soon on our company website. Would you be willing to share your code once finished with it? That’d be super helpful, thanks.

Thanks, @robphilp. It looks like that is almost working. The part that isn’t working is grabbing the value of the URL parameter. If I hard code the value of the $teamMember variable, it works.

$teamMember = 'stephen-bau';

But if I try to use this code, it doesn’t work:

$teamMember = $this->_env['env']['url']['team-member'];

So, it looks like the _env variable doesn’t have a value until the DataSource class processes the parameters, which appears to be too late in the process for this to work. So, I need another way to find the value of the URL parameter. Any ideas?

@TheJester12, I can certainly document the process for pulling the Twitter feeds.

Are you sure you’re referencing the right system variable, or the right element within the array etc?

You can try dumping out the value of $this->_env: -

var_dump($this->_env); exit;

…and see what you get from that. I suspect that there must be a way to reference the URL parameters in this context, and perhaps a kindly symphony dev will drop by and let us know!!

I think the problem is that $this->_env['env']['url']['team-member'] may not be resolved until the grab() method is called, so when you try using it in the constructor it isn’t available to you. Try moving your modifications to $this->dsParamURL into the grab() method, anywhere before the include should do it.

Thanks, Nick. That works!

<?php

    require_once(TOOLKIT . '/class.datasource.php');

    Class datasourcetwitter_team extends Datasource{

        public $dsParamROOTELEMENT = 'twitter-team';
        public $dsParamURL;
        public $dsParamXPATH = '/statuses/status[position() &lt; 3]';
        public $dsParamCACHE = '30';
        public $dsParamTIMEOUT = '6';

        public $teamMember;
        public $twitterUsername;

        public function __construct(&$parent, $env=NULL, $process_params=true){
            parent::__construct($parent, $env, $process_params);
            $this->_dependencies = array();
        }

        public function about(){
            return array(
                     'name' => 'Twitter: Team',
                     'author' => array(
                            'name' => 'Stephen Bau',
                            'website' => 'http://home/domain7/site',
                            'email' => 'stephen@domain7.com'),
                     'version' => '1.0',
                     'release-date' => '2010-05-09T20:24:00+00:00');    
        }

        public function getSource(){
            return 'dynamic_xml';
        }

        public function allowEditorToParse(){
            return false;
        }

        public function grab(&$param_pool=NULL){

            $teamMember = $this->_env['env']['url']['team-member'];
            $twitterAccounts = array(
                'john-smith'     => 'jsmith',
                'jane-doe'       => 'jdoe',
                'bob-loblaw'     => 'blahblahblah',
                'stephen-bau'    => 'bauhouse'
            );
            $twitterUsername = $twitterAccounts[$teamMember];
            $this->dsParamURL = 'http://twitter.com/statuses/user_timeline/' . $twitterUsername . '.xml';

            $result = new XMLElement($this->dsParamROOTELEMENT);

            if(empty($twitterUsername)) return $this->emptyXMLSet();

            try{
                include(TOOLKIT . '/data-sources/datasource.dynamic_xml.php');
            }
            catch(FrontendPageNotFoundException $e){
                // Work around. This ensures the 404 page is displayed and
                // is not picked up by the default catch() statement below
                FrontendPageNotFoundExceptionHandler::render($e);
            }           
            catch(Exception $e){
                $result->appendChild(new XMLElement('error', $e->getMessage()));
                return $result;
            }   

            if($this->_force_empty_result) $result = $this->emptyXMLSet();
            return $result;
        }
    }

Here’s how I was pulling the tweets with a data source for each team member with the name, “Team: screenname”:

<xsl:choose>
    <xsl:when test="twitter and /data/*[name() = concat('twitter-', /data/team-profile/entry/twitter)]/status">
        <xsl:for-each select="/data/*[name() = concat('twitter-', /data/team-profile/entry/twitter)]/status">
            <xsl:call-template name="list-tweets" />
        </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
        <ul>
            <xsl:for-each select="/data/twitter/status">
                <xsl:call-template name="list-tweets" />
            </xsl:for-each>
        </ul>
    </xsl:otherwise>
</xsl:choose>

Now, I only need a single data source to pull Twitter statuses for every team member using this:

<xsl:choose>
    <xsl:when test="twitter and /data/twitter-team/status">
        <xsl:for-each select="/data/twitter-team/status">
            <xsl:call-template name="list-tweets" />
        </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
        <ul>
            <xsl:for-each select="/data/twitter/status">
                <xsl:call-template name="list-tweets" />
            </xsl:for-each>
        </ul>
    </xsl:otherwise>
</xsl:choose>

My Twitter utility has a list-tweets template that uses Nick’s Twita@talinkahashifyer:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:import href="linkahashify.xsl"/>
<xsl:import href="twitter-format-date.xsl"/>
<xsl:import href="time-ago-friendly.xsl"/>

<xsl:template name="list-tweets">
    <li>
        <xsl:call-template name="linkahashify">
            <xsl:with-param name="tweet" select="text" />
        </xsl:call-template>
        <xsl:text> </xsl:text>
        <a class="time" href="http://twitter.com/{user/screen_name}/statuses/{id}">
            <xsl:call-template name="time-ago">
                <xsl:with-param name="date-and-time">
                    <xsl:call-template name="twitter-format-date">
                        <xsl:with-param name="date" select="created_at" />
                        <xsl:with-param name="format" select="'Y-n-dTO'" />
                    </xsl:call-template>
                </xsl:with-param>
            </xsl:call-template>
        </a>
    </li>
</xsl:template>

</xsl:stylesheet>

And I’m using a modified Twitter Format Date utility to provide the ISO date format to the Time Ago Friendly utility:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'" />
<!--

Description:

This is a date formatting utility for Twitter feeds, modified from the original date-time.xsl file. The named template "twitter-format-date" takes 2 parameters:

1. date - [required] takes a Twitter formatted date (<created_at>)
2. format - [optional] takes a format string.

Format options:

Y - year in 4 digits e.g. 1981, 1992, 2008
y - year in 2 digits e.g. 81, 92, 08
M - month as a full word e.g. January, March, September
m - month in 3 letters e.g. Jan, Mar, Sep
N - month in digits without leading zero
n - month in digits with leading zero
D - day with suffix and no leading zero e.g. 1st, 23rd
d - day in digits with leading zero e.g. 01, 09, 12, 25
x - day in digits with no leading zero e.g. 1, 9, 12, 25
O - time in 24-hours e.g. 18:30
o - time in 12-hours e.g. 6:30pm
W - weekday as a full word e.g. Monday, Tuesday
w - weekday in 3 letters e.g. Mon, Tue, Wed

Examples:

M       => January
d M     => 21 September
m D, y  => Sep 21st, 81
n-d-y   => 09-21-81
d/n/y   => 21/09/81
d/n/y t => 21/09/81 6:30pm

-->

<xsl:template name="twitter-format-date">
  <xsl:param name="date" />
  <xsl:param name="format" select="'d M, Y'" />

  <xsl:choose>
    <xsl:when test="string-length($format) &lt;= 10">
      <xsl:call-template name="twitter-date-controller">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$format"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>Error: format parameter is not correctly set. You have: </xsl:text>
      <xsl:value-of select="string-length($format)"/>
      <xsl:text>.</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="twitter-date-controller">
  <xsl:param name="date"/>
  <xsl:param name="format"/>
  <xsl:param name="letter" select="substring($format,1,1)"/>
  <xsl:param name="tletter" select="translate($letter,'DMNYOW','dmnyow')"/>

  <xsl:choose>
    <xsl:when test="$tletter = 'y'">
      <xsl:call-template name="twitter-format-year">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$letter"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$tletter = 'm'">
      <xsl:call-template name="twitter-format-month">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$letter"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$tletter = 'n'">
      <xsl:call-template name="twitter-format-month">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$letter"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$tletter = 'd'">
      <xsl:call-template name="twitter-format-day">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$letter"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$tletter = 'x'">
      <xsl:call-template name="twitter-format-day">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$letter"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$tletter = 'o'">
      <xsl:call-template name="twitter-format-time">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$letter"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="$tletter = 'w'">
      <xsl:call-template name="twitter-format-weekday">
        <xsl:with-param name="date" select="$date"/>
        <xsl:with-param name="format" select="$letter"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$letter"/>
    </xsl:otherwise>
  </xsl:choose>

  <xsl:if test="$letter = not('')">
    <xsl:call-template name="twitter-date-controller">
      <xsl:with-param name="date" select="$date"/>
      <xsl:with-param name="format" select="substring($format,2)"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>

<xsl:template name="twitter-format-year">
  <xsl:param name="date"/>
  <xsl:param name="year" select="substring($date,27)"/>
  <xsl:param name="format" select="'y'"/>

  <xsl:choose>
    <xsl:when test="$format = 'y'">
      <xsl:value-of select="substring($year,3)"/>
    </xsl:when>
    <xsl:when test="$format = 'Y'">
      <xsl:value-of select="$year"/>
    </xsl:when>
  </xsl:choose>
</xsl:template>

<xsl:template name="twitter-format-month">
  <xsl:param name="date"/>
  <xsl:param name="month" select="translate(substring($date,5,3),$uppercase,$lowercase)"/>
  <xsl:param name="format" select="'m'"/>
  <xsl:param name="month-word">
    <xsl:choose>
      <xsl:when test="$month = 'jan'">January</xsl:when>
      <xsl:when test="$month = 'feb'">February</xsl:when>
      <xsl:when test="$month = 'mar'">March</xsl:when>
      <xsl:when test="$month = 'apr'">April</xsl:when>
      <xsl:when test="$month = 'may'">May</xsl:when>
      <xsl:when test="$month = 'jun'">June</xsl:when>
      <xsl:when test="$month = 'jul'">July</xsl:when>
      <xsl:when test="$month = 'aug'">August</xsl:when>
      <xsl:when test="$month = 'sep'">September</xsl:when>
      <xsl:when test="$month = 'oct'">October</xsl:when>
      <xsl:when test="$month = 'nov'">November</xsl:when>
      <xsl:when test="$month = 'dec'">December</xsl:when>
    </xsl:choose>
  </xsl:param>

  <xsl:param name="month-digit">
    <xsl:choose>
      <xsl:when test="$month = 'jan'">01</xsl:when>
      <xsl:when test="$month = 'feb'">02</xsl:when>
      <xsl:when test="$month = 'mar'">03</xsl:when>
      <xsl:when test="$month = 'apr'">04</xsl:when>
      <xsl:when test="$month = 'may'">05</xsl:when>
      <xsl:when test="$month = 'jun'">06</xsl:when>
      <xsl:when test="$month = 'jul'">07</xsl:when>
      <xsl:when test="$month = 'aug'">08</xsl:when>
      <xsl:when test="$month = 'sep'">09</xsl:when>
      <xsl:when test="$month = 'oct'">10</xsl:when>
      <xsl:when test="$month = 'nov'">11</xsl:when>
      <xsl:when test="$month = 'dec'">12</xsl:when>
    </xsl:choose>
  </xsl:param>

  <xsl:choose>
    <xsl:when test="$format = 'm'">
      <xsl:value-of select="substring($month-word, 1,3)"/>
    </xsl:when>
    <xsl:when test="$format = 'M'">
      <xsl:value-of select="$month-word"/>
    </xsl:when>
    <xsl:when test="$format = 'n'">
      <xsl:value-of select="format-number($month-digit, '00')"/>
    </xsl:when>
    <xsl:when test="$format = 'N'">
      <xsl:value-of select="format-number($month-digit, '0')"/>
    </xsl:when>
  </xsl:choose>

</xsl:template>

<xsl:template name="twitter-format-day">
  <xsl:param name="date"/>
  <xsl:param name="day" select="format-number(substring($date,9,2),'00')"/>
  <xsl:param name="format" select="'d'"/>
  <xsl:param name="suffix">
    <xsl:choose>
      <xsl:when test="(substring($day,2) = 1) and not(substring($day,1,1) = 1)">st</xsl:when>
      <xsl:when test="(substring($day,2) = 2) and not(substring($day,1,1) = 1)">nd</xsl:when>
      <xsl:when test="(substring($day,2) = 3) and not(substring($day,1,1) = 1)">Rd</xsl:when>
      <xsl:otherwise>th</xsl:otherwise>
    </xsl:choose>
  </xsl:param>

  <xsl:choose>
    <xsl:when test="$format = 'd'">
      <xsl:value-of select="$day"/>
    </xsl:when>
    <xsl:when test="$format = 'x'">
      <xsl:value-of select="format-number($day,'0')"/>
    </xsl:when>
    <xsl:when test="$format = 'D'">
      <xsl:value-of select="format-number($day,'0')"/>
      <sup><xsl:value-of select="$suffix"/></sup>
    </xsl:when>
  </xsl:choose>

</xsl:template>

<!--
  Tue Feb 10 15:40:27 +0000 2009
-->

<xsl:template name="twitter-format-time">
  <xsl:param name="date"/>
  <xsl:param name="time" select="substring($date,12,8)" />
  <xsl:param name="hour" select="substring-before($time, ':')"/>
  <xsl:param name="minute" select="substring-after($time, ':')"/>
  <xsl:param name="format" select="'O'"/>
  <xsl:choose>
    <xsl:when test="$format = 'O'">
      <xsl:value-of select="$time"/>
    </xsl:when>
    <xsl:when test="$format = 'o'">
      <xsl:choose>
        <xsl:when test="$hour mod 12 = 0">12</xsl:when>
        <xsl:otherwise><xsl:value-of select="($hour mod 12)"/></xsl:otherwise>
      </xsl:choose>

      <xsl:value-of select="concat(':',$minute)"/>

      <xsl:choose>
        <xsl:when test="$hour &lt; 12">am</xsl:when>
        <xsl:otherwise>pm</xsl:otherwise>
      </xsl:choose>
    </xsl:when>
  </xsl:choose>
</xsl:template>

<xsl:template name="twitter-format-weekday">
  <xsl:param name="date" />
  <xsl:param name="weekday" select="translate(substring($date,1,3),$uppercase,$lowercase)" />
  <xsl:param name="format" select="'w'"/>

  <xsl:param name="day-name">
    <xsl:choose>
      <xsl:when test="$weekday = 'sun'">Sunday</xsl:when>
      <xsl:when test="$weekday = 'mon'">Monday</xsl:when>
      <xsl:when test="$weekday = 'tue'">Tuesday</xsl:when>
      <xsl:when test="$weekday = 'wed'">Wednesday</xsl:when>
      <xsl:when test="$weekday = 'thu'">Thursday</xsl:when>
      <xsl:when test="$weekday = 'fri'">Friday</xsl:when>
      <xsl:when test="$weekday = 'sat'">Satday</xsl:when>
    </xsl:choose>
  </xsl:param>

  <xsl:choose>
    <xsl:when test="$format = 'W'">
      <xsl:value-of select="$day-name"/>
    </xsl:when>
    <xsl:when test="$format = 'w'">
      <xsl:value-of select="substring($day-name,1,3)"/>
    </xsl:when>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

It seems the only issue left is figure out how to compensate for different time zones for the status date/time.

Wow, this is great. Thanks, I’ll be following this tutorial sometime in the next month. Might have questions then!

Don’t you love it when the pieces of a jigsaw come together? :-)

That’s what is so great about this community. The pieces were already there. The XSLT library on this site is fantastic.

I’ve been trying to build a proof-of-concept site using Symphony that takes our existing agency site, built on our proprietary system, and rebuilds it with Symphony using only the core extensions. Most of the problems I have come up against have been solved by an XSLT utility.

Stephen, have you thought about making this an extension with a Preferences panel where one could add a Twitter username alongside the authors? That would be a great extension!

Hmm. That’s not a bad idea. What would be even better is if you could point to a section with the URL parameter field and Twitter screen name field and it would automatically build the data source for you. Let me see what I can do.

Edit: No need for an extension. Just use parameter output to filter the dynamic XML data source.

I love it when a plan comes together!

The alternative is to set their Twitter username to be the Output Parameter of your Person data source, so then it is in a parameter ready for use in the Dynamic XML DS.

You’re right, Nick. I had thought of that, and it would be much simpler. But I wanted the URL structure to be consistent. Not all of the team members have a twitter account (o_O). And there are other important items that need to filter by the $team-member parameter.

I had thought that I could add another URL parameter for twitter and only pass the parameter to the URL string if the twitter screen name was available, but if just the team member handle was provided in the URL (for example, if someone was just typing the name in), the view would change.

So this works exactly how I want it to.

The other other alternative is to create a second DS with the same filters as your “person” one, but to have no elements output into the XML and just create the output parameter. Slightly wasteful, but useful nonetheless if you’re using this as a case study of native functionality only (without custom code).

Well, you’ve dunn it again. All I needed to do was to use the same data source for each Team Profile and select the Twitter field as the Parameter Output field. Then I just filter the Dynamic XML data source like so:

http://twitter.com/statuses/user_timeline/{$ds-team-profile}.xml

As you say, it’s a better way to demonstrate that there is no need for such hackery as I’ve just put myself through.

Guys, please can you help me. I use Twitter Format Date utility and Time Ago Friendly utility, but my tweets displayed with GMT +0, can i set GMT +4 ?

You could try the EXSLT library using the date:add-duration function/template to add on four hours to every date before formatting...

Ok, I add date:add-duration template to my tweets utility and i include the EXSLT namespaces. But i understand how can implementation this?

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details