@@ -0,0 +1,406 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The extension class used by twig..
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Validator
|
||||
*/
|
||||
class Ai1ec_Twig_Ai1ec_Extension extends Twig_Extension {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object
|
||||
*/
|
||||
protected $_registry;
|
||||
|
||||
/**
|
||||
* Inject the registry object.
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
*/
|
||||
public function set_registry( Ai1ec_Registry_Object $registry ) {
|
||||
$this->_registry = $registry;
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Twig_Extension::getFunctions()
|
||||
*/
|
||||
public function getFunctions() {
|
||||
return array(
|
||||
'wp_nonce_field' => new Twig_Function_Method( $this, 'wp_nonce_field' ),
|
||||
'do_meta_boxes' => new Twig_Function_Method( $this, 'do_meta_boxes' ),
|
||||
'fb' => new Twig_Function_Method( $this, 'fb' ),
|
||||
'ai1ec_disable_content_output' => new Twig_Function_Method( $this, 'ai1ec_disable_content_output' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Twig callback - return a list of filters registered by this extension.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters() {
|
||||
return array(
|
||||
new Twig_SimpleFilter( 'truncate', array( $this, 'truncate' ) ),
|
||||
new Twig_SimpleFilter( 'timespan', array( $this, 'timespan' ) ),
|
||||
new Twig_SimpleFilter( 'avatar', array( $this, 'avatar' ) ),
|
||||
new Twig_SimpleFilter( 'avatar_url', array( $this, 'avatar_url' ) ),
|
||||
new Twig_SimpleFilter( 'remove_avatar_url', array( $this, 'remove_avatar_url' ) ),
|
||||
new Twig_SimpleFilter( 'remove_paragraph', array( $this, 'remove_paragraph' ) ),
|
||||
new Twig_SimpleFilter( 'hour_to_datetime', array( $this, 'hour_to_datetime' ) ),
|
||||
new Twig_SimpleFilter( 'weekday', array( $this, 'weekday' ) ),
|
||||
new Twig_SimpleFilter( 'day', array( $this, 'day' ) ),
|
||||
new Twig_SimpleFilter( 'month', array( $this, 'month' ) ),
|
||||
new Twig_SimpleFilter( 'year', array( $this, 'year' ) ),
|
||||
new Twig_SimpleFilter( 'theme_img_url', array( $this, 'theme_img_url' ) ),
|
||||
new Twig_SimpleFilter( 'date_i18n', array( $this, 'date_i18n' ) ),
|
||||
new Twig_SimpleFilter( 'dropdown_filter', array( $this, 'dropdown_filter' ),
|
||||
array( 'is_safe' => array( 'html' ) )
|
||||
),
|
||||
new Twig_SimpleFilter( '__', 'Ai1ec_I18n::__' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Twig callback - return a list of tests registered by this extension.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTests() {
|
||||
return array(
|
||||
new Twig_SimpleTest( 'string', array( $this, 'is_string' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML markup for the post's "avatar" image according conditional
|
||||
* fallback model.
|
||||
*
|
||||
* Accepts an ordered array of named avatar $fallbacks. Also accepts a string
|
||||
* of space-separated classes to add to the default classes.
|
||||
* @param Ai1ec_Event $event The event to get the avatar for
|
||||
* @param array|null $fallback_order Order of fallback in searching for
|
||||
* images, or null to use default
|
||||
* @param string $classes A space-separated list of CSS classes
|
||||
* to apply to the outer <div> element.
|
||||
* @param boolean $wrap_permalink Whether to wrap the element in a link
|
||||
* to the event details page.
|
||||
*
|
||||
* @return string String of HTML if image is found
|
||||
*/
|
||||
public function avatar(
|
||||
Ai1ec_Event $event,
|
||||
$fallback_order = null,
|
||||
$classes = '',
|
||||
$wrap_permalink = true
|
||||
) {
|
||||
return $this->_registry->get( 'view.event.avatar' )
|
||||
->get_event_avatar(
|
||||
$event,
|
||||
$fallback_order,
|
||||
$classes,
|
||||
$wrap_permalink
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug function to be used in twig templates with Firebug/FirePHP
|
||||
*
|
||||
* @param mixed $object
|
||||
*/
|
||||
public function fb( $object ) {
|
||||
if ( function_exists( 'fb' ) ) {
|
||||
fb( $object );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get URL for avatar.
|
||||
*
|
||||
* Accepts an ordered array of named avatar $fallbacks.
|
||||
* @param Ai1ec_Event $event The event to get the avatar for.
|
||||
* @param array|null $fallback_order Order of fallback in searching for
|
||||
* images, or null to use default.
|
||||
*
|
||||
* @return string URL if image is found.
|
||||
*/
|
||||
public function avatar_url(
|
||||
Ai1ec_Event $event,
|
||||
$fallback_order = null
|
||||
) {
|
||||
return $this->_registry->get( 'view.event.avatar' )
|
||||
->get_event_avatar_url(
|
||||
$event,
|
||||
$fallback_order
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the avatar url from the content
|
||||
*
|
||||
* Accepts an ordered array of named avatar $fallbacks.
|
||||
* @param Ai1ec_Event $event The event to get the avatar for.
|
||||
* @param array|null $fallback_order Order of fallback in searching for
|
||||
* images, or null to use default.
|
||||
*
|
||||
* @return string URL if image is found.
|
||||
*/
|
||||
public function remove_avatar_url(
|
||||
$content
|
||||
) {
|
||||
return $this->_registry->get( 'view.event.avatar' )
|
||||
->remove_avatar_url( $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the First paragraph (<p>....</p>) from the content
|
||||
* @return
|
||||
* <p>This is a text</p> returns This is a text
|
||||
* <p><p>This is a text</p></p> returns <p>This is a text</p>
|
||||
*/
|
||||
public function remove_paragraph( $content ) {
|
||||
if ( preg_match( '/^<p>(.+)<\\/p>$/is', $content, $matches ) ) {
|
||||
return $matches[1];
|
||||
} else {
|
||||
return $content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if provided value is a string.
|
||||
*
|
||||
* @param mixed $var Suspected string
|
||||
*
|
||||
* @return boolean True if it is a string, false otherwise.
|
||||
*/
|
||||
public function is_string( $var ) {
|
||||
return is_string( $var );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an hour to an Ai1ec_Date_Time object.
|
||||
*
|
||||
* @param int $hour
|
||||
*
|
||||
* @return Ai1ec_Date_Time
|
||||
*/
|
||||
public function hour_to_datetime( $hour ) {
|
||||
return $this->_registry->get( 'date.time', 'now', 'sys.default' )
|
||||
->set_time( $hour, 0, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the weekday.
|
||||
*
|
||||
* @param int $unix_timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function weekday( $unix_timestamp ) {
|
||||
return $this->_registry->get( 'date.time', $unix_timestamp )
|
||||
->format_i18n( 'D' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the day.
|
||||
*
|
||||
* @param int $unix_timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function day( $unix_timestamp ) {
|
||||
return $this->_registry->get( 'date.time', $unix_timestamp )
|
||||
->format_i18n( 'j' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the month.
|
||||
*
|
||||
* @param int $unix_timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function month( $unix_timestamp ) {
|
||||
return $this->_registry->get( 'date.time', $unix_timestamp )
|
||||
->format_i18n( 'M' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date's year
|
||||
*
|
||||
* @param int $unix_timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function year( $unix_timestamp ) {
|
||||
return $this->_registry->get( 'date.time', $unix_timestamp )
|
||||
->format_i18n( 'Y' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL of the given image file in the calendar theme's directory.
|
||||
*
|
||||
* @param int $unix_timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function theme_img_url( $image ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
return $loader->get_file( $image, array(), false )->get_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internationalize the given UNIX timestamp with the given format string.
|
||||
*
|
||||
* @param int $unix_timestamp
|
||||
* @param string $format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function date_i18n( $unix_timestamp, $format ) {
|
||||
return $this->_registry->get( 'date.time', $unix_timestamp )
|
||||
->format_i18n( $format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a string after $length characters, appending $read_more string
|
||||
* at end of truncation.
|
||||
*
|
||||
* @param number $length Length to truncate string to.
|
||||
* @param string $read_more What string to append if truncated.
|
||||
* @param string $html_entities Whether to treat input string as HTML with
|
||||
* possible &asdf; entities
|
||||
* @return string
|
||||
*/
|
||||
public function truncate(
|
||||
$string,
|
||||
$length = 35,
|
||||
$read_more = '...',
|
||||
$html_entities = true
|
||||
) {
|
||||
// Truncate multibyte encodings differently, if supported.
|
||||
if ( function_exists( 'mb_strimwidth' ) ) {
|
||||
// First decode entities if requested.
|
||||
if ( $html_entities ) {
|
||||
$string = html_entity_decode( $string, ENT_QUOTES, 'UTF-8' );
|
||||
}
|
||||
// Truncate string.
|
||||
$string = mb_strimwidth( $string, 0, $length, $read_more, 'UTF-8' );
|
||||
// Reencode entities if requested.
|
||||
if ( $html_entities ) {
|
||||
$string = htmlentities( $string, ENT_QUOTES, 'UTF-8' );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// First decode entities if requested.
|
||||
if ( $html_entities ) {
|
||||
$string = html_entity_decode( $string, ENT_QUOTES );
|
||||
}
|
||||
// Truncate string.
|
||||
$read_more = strlen( $string ) > 35 ? $read_more : '';
|
||||
$string = substr( $string, 0, 35 ) . $read_more;
|
||||
// Reencode entities if requested.
|
||||
if ( $html_entities ) {
|
||||
$string = html_entity_decode( $string, ENT_QUOTES );
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter string allowing ampersand symbols to be displayed.
|
||||
* at end of truncation.
|
||||
*
|
||||
* @param string $string String to process.
|
||||
* @return string
|
||||
*/
|
||||
public function dropdown_filter(
|
||||
$string
|
||||
) {
|
||||
$string = htmlspecialchars( $string );
|
||||
$string = preg_replace( '/&/', '&', $string );
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a timespan HTML block for an event.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event to generate timespan for.
|
||||
* @param string $start_date_display Start date display format.
|
||||
*
|
||||
* @return string Rendered HTML timespan block.
|
||||
*/
|
||||
public function timespan(
|
||||
Ai1ec_Event $event,
|
||||
$start_date_display = 'long'
|
||||
) {
|
||||
return $this->_registry->get( 'view.event.time' )
|
||||
->get_timespan_html( $event, $start_date_display );
|
||||
}
|
||||
|
||||
/**
|
||||
* Meta-Box template function
|
||||
*
|
||||
* @since 2.5.0
|
||||
*
|
||||
* @param string|object $screen Screen identifier
|
||||
* @param string $context box context
|
||||
* @param mixed $object gets passed to the box callback function as first parameter
|
||||
* @return int number of meta_boxes
|
||||
*/
|
||||
public function do_meta_boxes( $screen, $context, $object ) {
|
||||
do_meta_boxes( $screen, $context, $object );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve or display nonce hidden field for forms.
|
||||
*
|
||||
* The nonce field is used to validate that the contents of the form came from
|
||||
* the location on the current site and not somewhere else. The nonce does not
|
||||
* offer absolute protection, but should protect against most cases. It is very
|
||||
* important to use nonce field in forms.
|
||||
*
|
||||
* The $action and $name are optional, but if you want to have better security,
|
||||
* it is strongly suggested to set those two parameters. It is easier to just
|
||||
* call the function without any parameters, because validation of the nonce
|
||||
* doesn't require any parameters, but since crackers know what the default is
|
||||
* it won't be difficult for them to find a way around your nonce and cause
|
||||
* damage.
|
||||
*
|
||||
* The input name will be whatever $name value you gave. The input value will be
|
||||
* the nonce creation value.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Security
|
||||
* @since 2.0.4
|
||||
*
|
||||
* @param string $action Optional. Action name.
|
||||
* @param string $name Optional. Nonce name.
|
||||
* @param bool $referer Optional, default true. Whether to set the referer field for validation.
|
||||
* @param bool $echo Optional, default true. Whether to display or return hidden form field.
|
||||
* @return string Nonce field.
|
||||
*/
|
||||
public function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
|
||||
wp_nonce_field( $action, $name, $referer, $echo );
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
* @see Twig_ExtensionInterface::getName()
|
||||
*/
|
||||
public function getName() {
|
||||
return 'ai1ec';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks into the_content filter to disable its output.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*/
|
||||
public function ai1ec_disable_content_output() {
|
||||
$this->_registry->get( 'calendar.state' )->set_append_content( false );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The class which handles Twig cache rescan process.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Twig
|
||||
*/
|
||||
class Ai1ec_Twig_Cache extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Rescan cache for writable directory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rescan() {
|
||||
$cache_dir = $this->_registry->get( 'theme.loader' )
|
||||
->get_cache_dir( true );
|
||||
$render_json = $this->_registry->get(
|
||||
'http.response.render.strategy.json'
|
||||
);
|
||||
$output['data'] = array(
|
||||
'state' => (int)(false !== $cache_dir),
|
||||
);
|
||||
$render_json->render( $output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Twig cache as unavailable and notifies admin.
|
||||
*
|
||||
* @param string $cache_dir Cache dir.
|
||||
*
|
||||
* @throws Ai1ec_Bootstrap_Exception
|
||||
*/
|
||||
public function set_unavailable( $cache_dir = AI1EC_TWIG_CACHE_PATH ) {
|
||||
$this->_registry->get( 'model.settings' )
|
||||
->set( 'twig_cache', AI1EC_CACHE_UNAVAILABLE );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Wrapper for Twig_Environment
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Twig
|
||||
*/
|
||||
class Ai1ec_Twig_Environment extends Twig_Environment {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Registry_Object The registry Object.
|
||||
*/
|
||||
protected $_registry = null;
|
||||
|
||||
/**
|
||||
* Loads a template by name.
|
||||
*
|
||||
* @param string $name The template name
|
||||
* @param integer $index The index if it is an embedded template
|
||||
*
|
||||
* @return Twig_TemplateInterface A template instance representing the given template name
|
||||
*/
|
||||
public function loadTemplate( $name, $index = null ) {
|
||||
try {
|
||||
return parent::loadTemplate( $name, $index );
|
||||
} catch ( RuntimeException $excpt ) {
|
||||
/*
|
||||
* We should not rely on is_writable - WP Engine case.
|
||||
* I've made twig directory read-only and is_writable was returning
|
||||
* true.
|
||||
*/
|
||||
$this->_registry->get(
|
||||
'twig.cache'
|
||||
)->set_unavailable( $this->cache );
|
||||
/*
|
||||
* Some copy paste from original Twig method. Just to avoid first
|
||||
* error during rendering.
|
||||
*/
|
||||
$cls = $this->getTemplateClass( $name, $index );
|
||||
eval(
|
||||
'?>' .
|
||||
$this->compileSource(
|
||||
$this->getLoader()->getSource( $name ),
|
||||
$name
|
||||
)
|
||||
);
|
||||
return $this->loadedTemplates[$cls] = new $cls($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Ai1ec_Registry_Object
|
||||
*
|
||||
* @param Ai1ec_Registry_Object $registry
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_registry( Ai1ec_Registry_Object $registry ) {
|
||||
$this->_registry = $registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template.
|
||||
*
|
||||
* @param string $name The template name
|
||||
* @param array $context An array of parameters to pass to the template
|
||||
*
|
||||
* @return string The rendered template
|
||||
*
|
||||
* @throws Twig_Error_Loader When the template cannot be found
|
||||
* @throws Twig_Error_Syntax When an error occurred during compilation
|
||||
* @throws Twig_Error_Runtime When an error occurred during rendering
|
||||
*/
|
||||
public function render( $name, array $context = array() ) {
|
||||
try {
|
||||
return parent::render( $name, $context );
|
||||
} catch ( Exception $excpt ) {
|
||||
if (
|
||||
! defined( 'AI1EC_DEBUG' ) ||
|
||||
! AI1EC_DEBUG
|
||||
) {
|
||||
return $this->_handle_render_exception( $name, $context );
|
||||
}
|
||||
throw $excpt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches calendar theme to vortex.
|
||||
*
|
||||
* @return void Method does not return.
|
||||
*
|
||||
* @throws Ai1ec_Bootstrap_Exception
|
||||
*/
|
||||
public function switch_to_vortex() {
|
||||
$this->_registry->get( 'theme.loader' )->switch_to_vortex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles rendering exception. Switches to Vortex theme and tries to
|
||||
* re-render view. If it doesn't help it returns default warning.
|
||||
*
|
||||
* @param string $name Template name.
|
||||
* @param array $context An array of parameters to pass to the template.
|
||||
*
|
||||
* @return string Rendered or default error string.
|
||||
*/
|
||||
protected function _handle_render_exception( $name, array $context ) {
|
||||
register_shutdown_function( array( $this, 'switch_to_vortex' ) );
|
||||
return '<div class="ai1ec-alert ai1ec-alert-danger">' .
|
||||
Ai1ec_I18n::__( 'The calendar is temporarily disabled due to a rendering error. Please <a href="javascript:location.reload();">reload the page</a>.' ) .
|
||||
'</div>';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Wrapper for Twig_Loader_Filesystem
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.1
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.Twig
|
||||
*/
|
||||
class Ai1ec_Twig_Loader_Filesystem extends Twig_Loader_Filesystem {
|
||||
|
||||
/**
|
||||
* Gets the cache key to use for the cache for a given template name.
|
||||
*
|
||||
* @param string $name The name of the template to load
|
||||
*
|
||||
* @return string The cache key
|
||||
*
|
||||
* @throws Twig_Error_Loader When $name is not found.
|
||||
*/
|
||||
public function getCacheKey( $name ) {
|
||||
// namespace style separators avoid OS colisions.
|
||||
$cache_key = str_replace( '/', '\\', $this->findTemplate( $name ) );
|
||||
// make path relative
|
||||
$cache_key = str_replace(
|
||||
str_replace( '/', '\\', WP_PLUGIN_DIR . DIRECTORY_SEPARATOR ) ,
|
||||
'',
|
||||
$cache_key
|
||||
);
|
||||
return $cache_key;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user