/**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) == 0) {
         throw new \InvalidArgumentException('"ifAny" helper expects at least one argument.');
     }
     $condition = false;
     foreach ($parsed_args as $parsed_arg) {
         $value = $context->get($parsed_arg);
         if ($value instanceof String) {
             // Casting any object of \Handlebars\Str will have false
             // positive result even for those with empty internal strings.
             // Thus we need to check internal string of such objects.
             $value = $value->getString();
         }
         if ($value) {
             $condition = true;
             break;
         }
     }
     if ($condition) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
     } else {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     return $buffer;
 }
Exemple #2
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $tmp = $context->get($args);
     $buffer = '';
     if (!$tmp) {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     } elseif (is_array($tmp) || $tmp instanceof \Traversable) {
         $isList = is_array($tmp) && array_keys($tmp) === range(0, count($tmp) - 1);
         $index = 0;
         $lastIndex = $isList ? count($tmp) - 1 : false;
         foreach ($tmp as $key => $var) {
             $specialVariables = array('@index' => $index, '@first' => $index === 0, '@last' => $index === $lastIndex);
             if (!$isList) {
                 $specialVariables['@key'] = $key;
             }
             $context->pushSpecialVariables($specialVariables);
             $context->push($var);
             $template->setStopToken('else');
             $template->rewind();
             $buffer .= $template->render($context);
             $context->pop();
             $context->popSpecialVariables();
             $index++;
         }
         $template->setStopToken(false);
     }
     return $buffer;
 }
Exemple #3
0
 /**
  * Execute the helper
  * {{url 'filename'}}
  * {{url 'filename' this }}
  * {{url 'filename' with {"id":12, "slug":"test"} }}
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $buffer = '';
     $args = $template->parseArguments($args);
     if (count($args) < 2) {
         throw new \Exception("Handlerbars Helper 'compare' needs 2 parameters");
     }
     $operator = isset($args[2]) ? $args[2]->getString() : '==';
     $lvalue = $context->get($args[0]);
     $rvalue = $context->get($args[1]);
     $equal = function ($l, $r) {
         return $l == $r;
     };
     $strictequal = function ($l, $r) {
         return $l === $r;
     };
     $different = function ($l, $r) {
         return $l != $r;
     };
     $lower = function ($l, $r) {
         return $l < $r;
     };
     $greatter = function ($l, $r) {
         return $l > $r;
     };
     $lowOrEq = function ($l, $r) {
         return $l <= $r;
     };
     $greatOrEq = function ($l, $r) {
         return $l >= $r;
     };
     $operators = ['==' => 'equal', '===' => 'strictequal', '!=' => 'different', '<' => 'lower', '>' => 'greatter', '<=' => 'lowOrEq', '>=' => 'greatOrEq'];
     if (!$operators[$operator]) {
         throw new \Exception("Handlerbars Helper 'compare' doesn't know the operator " . $operator);
     }
     $tmp = ${$operators}[$operator]($lvalue, $rvalue);
     $buffer = '';
     $context->push($context->last());
     if ($tmp) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
         $template->discard($context);
     } else {
         $template->setStopToken('else');
         $template->discard($context);
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     $context->pop();
     return $buffer;
 }
Exemple #4
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $tmp = $context->get($args);
     if (!$tmp) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
     } else {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     return $buffer;
 }
Exemple #5
0
 /**
  * Execute the helper
  * {{#formErrors login}}
  *  <ul>
  *    {{#each errors}}
  *    <li>{{this}}</li>
  *    {{/each}}
  *  </ul>
  * {{/formErrors}}
  * Catch form validation's erros. 
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $buffer = '';
     $args = $template->parseArguments($args);
     $errors = \Session::get('errors', new \Illuminate\Support\MessageBag());
     // no form specified
     // return empty buffer
     if (!count($args)) {
         return $buffer;
     }
     // if MessageBag does not exists
     // return empty buffer
     if (!method_exists($errors, 'hasBag')) {
         return $buffer;
     }
     // Defined MessageBag exists
     // so we push errors list to the context
     if ($errors->hasBag($args[0])) {
         $context->push(['errors' => $errors->{$args[0]}->all()]);
         $template->rewind();
         $buffer .= $template->render($context);
         $context->pop();
         return $buffer;
     }
     // return empty buffer
     return $buffer;
 }
Exemple #6
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $context->with($args);
     $buffer = $template->render($context);
     $context->pop();
     return $buffer;
 }
Exemple #7
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template  $template The template instance
  * @param \Handlebars\Context   $context  The current context
  * @param \Handlebars\Arguments $args     The arguments passed the the helper
  * @param string                $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $positionalArgs = $args->getPositionalArguments();
     $context->with($positionalArgs[0]);
     $buffer = $template->render($context);
     $context->pop();
     return $buffer;
 }
Exemple #8
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $buffer = '';
     $cart = \Subbly\Subbly::api('subbly.cart')->count();
     if (!count($cart)) {
         $template->setStopToken('else');
         $template->discard($context);
         $template->setStopToken(false);
         $buffer = $template->render($context);
     } else {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
         $template->discard($context);
     }
     return $buffer;
 }
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     // $args = $this->parseArgs( $args );
     $user = $context->get('user');
     if (!$user) {
         throw new \Exception("User need to be log-in to access to his addresses");
     }
     // Get Address
     // -----------------
     $options = ['where' => [['uid', '=', $user->uid]]];
     try {
         $addresses = Subbly::api('subbly.user_address')->findByUser($user, $options);
     } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
         return false;
     }
     if (!count($addresses)) {
         $addresses = false;
     }
     $buffer = '';
     if (!$addresses) {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     } elseif (is_array($addresses) || $addresses instanceof \Traversable) {
         $isList = is_array($addresses) && array_keys($addresses) === range(0, count($addresses) - 1);
         $index = 0;
         $lastIndex = $isList ? count($addresses) - 1 : false;
         foreach ($addresses as $key => $var) {
             $specialVariables = array('@index' => $index, '@first' => $index === 0, '@last' => $index === $lastIndex);
             if (!$isList) {
                 $specialVariables['@key'] = $key;
             }
             $context->pushSpecialVariables($specialVariables);
             $context->push($var);
             $template->setStopToken('else');
             $template->rewind();
             $buffer .= $template->render($context);
             $context->pop();
             $context->popSpecialVariables();
             $index++;
         }
         $template->setStopToken(false);
     }
     return $buffer;
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $resolved_args = array();
     foreach ($template->parseArguments($args) as $arg) {
         $resolved_args[] = $context->get($arg);
     }
     if ($this->evaluateCondition($resolved_args)) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
     } else {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     return $buffer;
 }
Exemple #11
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $parsedArgs = $template->parseArguments($args);
     $tmp = $context->get($parsedArgs[0]);
     $context->push($context->last());
     if (!$tmp) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
     } else {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     $context->pop();
     return $buffer;
 }
Exemple #12
0
 /**
  * Execute the helper
  * {{#isUserLogin}}
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $tmp = Subbly::api('subbly.user')->check();
     if (!$tmp) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
         $template->discard($context);
     } else {
         $context->push(['user' => Subbly::api('subbly.user')->currentUser()]);
         $template->setStopToken('else');
         $template->discard($context);
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     $context->pop();
     return $buffer;
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) != 2) {
         throw new \InvalidArgumentException('"ifEqual" helper expects exactly two arguments.');
     }
     $condition = $context->get($parsed_args[0]) == $context->get($parsed_args[1]);
     if ($condition) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
     } else {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     return $buffer;
 }
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $arguments = $this->split($args);
     $left = $this->getData($context, $arguments[0]);
     $operator = $arguments[1]['data'];
     $right = $this->getData($context, $arguments[2]);
     if ($this->compare($left, $operator, $right)) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
         $template->discard($context);
     } else {
         $template->setStopToken('else');
         $template->discard($context);
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     return $buffer;
 }
 /**
  * Execute the is Helper for Handlebars.php {{#is variable value}} code {{else}} alt code {{/is}}
  * OR {{#is user_logged_in}} code {{else}} alt code {{/is}}
  * OR {{#is is_user_logged_in}} code {{else}} alt code {{/is}}
  * OR {{#is home}} code {{else}} alt code {{/is}}
  * based off the IfHelper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public static function helper($template, $context, $args, $source)
 {
     $value = null;
     if (false !== strpos($args, ' ')) {
         $parts = explode(' ', $args);
         $args = $parts[0];
         $value = $parts[1];
     } else {
         if (in_array($args, self::if_checks())) {
             // fix alias - because is is_user is annouting..!
             if (false === strpos($args, 'is_')) {
                 $args = 'is_' . $args;
             }
             if (call_user_func($args)) {
                 $value = 1;
                 $args = 1;
             } else {
                 $value = null;
                 $args = 1;
             }
         }
     }
     if (is_numeric($args)) {
         $tmp = $args;
     } else {
         $tmp = $context->get($args);
     }
     $context->push($context->last());
     if ($tmp === $value) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
         $template->discard($context);
     } else {
         $template->setStopToken('else');
         $template->discard($context);
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     $context->pop();
     return $buffer;
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) != 2) {
         throw new \InvalidArgumentException('"replace" helper expects exactly two arguments.');
     }
     $search = $context->get($parsed_args[0]);
     $replacement = $context->get($parsed_args[1]);
     $subject = (string) $template->render($context);
     return str_replace($search, $replacement, $subject);
 }
Exemple #17
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $isLogin = $context->get('isUserLogin');
     if (!$isLogin) {
         throw new \Exception("User need to be log-in to access to his addresses");
     }
     $props = $this->parseProps($args, $context);
     $args = $this->parseArgs($args);
     $id = false;
     $buffer = '';
     // no properties
     // so address's ID is in URL
     // or is th first arguments
     if (!$props) {
         $id = count($args) === 0 ? $context->get('inputs.addressId') : $args[0];
     } else {
         if (array_key_exists('addressId', $props)) {
             $id = $props['addressId'];
         }
     }
     // new address
     if (!$id) {
         return $template->render($context);
     }
     // throw new \InvalidArgumentException( 'Can not find user address ID');
     // Get Address
     // -----------------
     $user = $context->get('user');
     try {
         $options = ['where' => [['uid', '=', $user->uid]]];
         $address = Subbly::api('subbly.user_address')->find($id, $options)->toArray();
     } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
         throw new \InvalidArgumentException($e->getMessage());
     }
     $buffer = '';
     $context->push($address);
     $template->rewind();
     $buffer .= $template->render($context);
     $context->pop();
     return $buffer;
 }
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $args = $this->ParseArgs($args);
     $dataSelector = implode(".", array_slice($args, 0, count($args) - 1));
     $tmp = $context->get($dataSelector);
     if (count($args) == 1) {
         $limit = 0;
     } else {
         $limit = $args[count($args) - 1];
     }
     $buffer = '';
     if (!$tmp) {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     } elseif (is_array($tmp) || $tmp instanceof \Traversable) {
         $isList = is_array($tmp) && array_keys($tmp) === range(0, count($tmp) - 1);
         $index = 0;
         $lastIndex = $isList ? count($tmp) - 1 : false;
         foreach ($tmp as $key => $var) {
             if ($index + 1 > $limit && $limit > 0) {
                 continue;
             }
             $specialVariables = array('@index' => $index, '@first' => $index === 0, '@last' => $index === $lastIndex);
             if (!$isList) {
                 $specialVariables['@key'] = $key;
             }
             $context->pushSpecialVariables($specialVariables);
             $context->push($var);
             $template->setStopToken('else');
             $template->rewind();
             $buffer .= $template->render($context);
             $context->pop();
             $context->popSpecialVariables();
             $index++;
         }
         $template->setStopToken(false);
     }
     return $buffer;
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     // Get block name
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) != 1) {
         throw new \InvalidArgumentException('"ifOverridden" helper expects exactly one argument.');
     }
     $block_name = $context->get(array_shift($parsed_args));
     // Check condition and render blocks
     if ($this->blocksStorage->has($block_name)) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
     } else {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     return $buffer;
 }
Exemple #20
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     if (is_numeric($args)) {
         $tmp = $args;
     } else {
         $tmp = $context->get($args);
     }
     $context->push($context->last());
     if ($tmp) {
         $template->setStopToken('else');
         $buffer = $template->render($context);
         $template->setStopToken(false);
         $template->discard($context);
     } else {
         $template->setStopToken('else');
         $template->discard($context);
         $template->setStopToken(false);
         $buffer = $template->render($context);
     }
     $context->pop();
     return $buffer;
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) != 1) {
         throw new \InvalidArgumentException('"repeat" helper expects exactly one argument.');
     }
     $times = intval($context->get($parsed_args[0]));
     if ($times < 0) {
         throw new \InvalidArgumentException('The first argument of "repeat" helper has to be greater than or equal to 0.');
     }
     $string = $template->render($context);
     return str_repeat($string, $times);
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     // Get block name
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) != 1) {
         throw new \InvalidArgumentException('"block" helper expects exactly one argument.');
     }
     $block_name = $context->get(array_shift($parsed_args));
     // If the block is not overridden render and show the default value
     if (!$this->blocksStorage->has($block_name)) {
         return $template->render($context);
     }
     $content = $this->blocksStorage->get($block_name);
     // Show overridden content
     return $content;
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     // Get block name
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) != 1) {
         throw new \InvalidArgumentException('"override" helper expects exactly one argument.');
     }
     $block_name = $context->get(array_shift($parsed_args));
     // We need to provide unlimited inheritence level. Rendering is started
     // from the deepest level template. If the content is in the block
     // storage it is related with the deepest level template. Thus we do not
     // need to override it.
     if (!$this->blocksStorage->has($block_name)) {
         $this->blocksStorage->set($block_name, $template->render($context));
     }
 }
Exemple #24
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $props = $this->parseProps($args, $context);
     $args = $this->parseArgs($args);
     $field = 'id';
     $id = false;
     $buffer = '';
     // no properties
     // so product's ID is in URL
     // or is th first arguments
     if (!$props) {
         $id = count($args) === 0 ? $context->get('inputs.productId') : $args[0];
     } else {
         if (array_key_exists('productId', $props)) {
             $id = $props['productId'];
         } else {
             if (array_key_exists('productSku', $props)) {
                 $id = $props['productSku'];
                 $field = 'sku';
             }
         }
     }
     if (!$id) {
         throw new \InvalidArgumentException('Can not find product identifier');
     }
     // Product query
     // ----------------
     // TODO: add status restriction if
     // current user is not loggued to Backend
     $productOptions = ['includes' => ['images', 'categories', 'options', 'translations'], 'where' => [['status', '!=', 'draft'], ['status', '!=', 'hidden']]];
     // Get product
     // -----------------
     try {
         $product = \Subbly\Subbly::api('subbly.product')->find($id, $productOptions, $field)->toArray();
     } catch (\Exception $e) {
         throw new \InvalidArgumentException($e->getMessage());
     }
     $context->push($product);
     $template->rewind();
     $buffer .= $template->render($context);
     $context->pop();
     return $buffer;
 }
 /**
  * {@inheritdoc}
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     // Get name of the parent template
     $parsed_args = $template->parseArguments($args);
     if (count($parsed_args) != 1) {
         throw new \InvalidArgumentException('"extends" helper expects exactly one argument.');
     }
     $parent_template = $context->get(array_shift($parsed_args));
     // Render content inside "extends" block to override blocks
     $template->render($context);
     // We need another instance of \Handlebars\Template to render parent
     // template. It can be got from Handlebars engine, so get the engine.
     $handlebars = $template->getEngine();
     // Render the parent template
     $this->level++;
     $buffer = $handlebars->render($parent_template, $context);
     $this->level--;
     if ($this->level == 0) {
         // The template and all its parents are rendered. Clean up the
         // storage.
         $this->blocksStorage->clear();
     }
     return $buffer;
 }
Exemple #26
0
 /**
  * Execute the helper
  *
  * @param \Handlebars\Template $template The template instance
  * @param \Handlebars\Context  $context  The current context
  * @param array                $args     The arguments passed the the helper
  * @param string               $source   The source
  *
  * @return mixed
  */
 public function execute(Template $template, Context $context, $args, $source)
 {
     $props = $this->parseProps($args, $context);
     $args = $this->parseArgs($args);
     // Products query
     // ----------------
     $productsOptions = ['where' => [['status', '!=', 'draft'], ['status', '!=', 'hidden']]];
     // Includes
     // ----------------
     if (isset($props['includes']) && is_array($props['includes'])) {
         $productsOptions['includes'] = $props['includes'];
     }
     // Where
     // ----------------
     if (isset($props['where']) && is_array($props['where'])) {
         // $productsOptions['where'] = [];
         foreach ($props['where'] as $condition) {
             if (is_array($condition) && count($condition) == 3) {
                 $productsOptions['where'][] = $condition;
             }
         }
     }
     // Order By
     // ----------------
     if (isset($props['order_by']) && is_array($props['order_by'])) {
         $productsOptions['order_by'] = [];
         foreach ($props['order_by'] as $order) {
             if (is_array($order) && count($order) == 2) {
                 $productsOptions['order_by'][$order[0]] = $order[1];
             }
         }
     }
     // Offset & limit
     // ----------------
     if (isset($props['limit']) && is_integer($props['limit'])) {
         $productsOptions['limit'] = $props['limit'];
     }
     $offset = null;
     if (isset($props['offset']) && is_integer($props['offset']) && isset($productsOptions['limit'])) {
         $productsOptions['offset'] = $props['offset'];
     }
     if (!isset($productsOptions['offset']) && isset($props['page']) && is_integer($props['page'])) {
         $offset = ((int) $props['page'] - 1) * $productsOptions['limit'];
         $offset = $offset < 0 ? 0 : $offset;
     }
     $offset ?: 0;
     $productsOptions['offset'] = $offset;
     // Categories
     // ----------------
     $hasCategories = is_array($props) && (array_key_exists('category', $props) || array_key_exists('subcategory', $props));
     if ($hasCategories) {
         $categoriesOptions = [];
         if (isset($props['category'])) {
             $categoriesOptions[] = ['slug', $props['category']];
         }
         if (isset($props['subcategory'])) {
             $categoriesOptions[] = ['slug', $props['subcategory']];
         }
         if (count($categoriesOptions) > 0) {
             $categories = \Subbly\Subbly::api('subbly.category')->all(['has' => ['translations' => $categoriesOptions]]);
         } else {
             $hasCategories = false;
         }
     }
     if ($hasCategories && count($categories)) {
         $productsOptions['has']['categories'] = [];
         foreach ($categories as $category) {
             $productsOptions['has']['categories'][] = ['category_id', $category->id];
         }
     }
     // Get products
     // -----------------
     $products = \Subbly\Subbly::api('subbly.product')->all($productsOptions)->toArray();
     $buffer = '';
     if (!$products) {
         $template->setStopToken('else');
         $template->discard();
         $template->setStopToken(false);
         $buffer = $template->render($context);
     } elseif (is_array($products) || $products instanceof \Traversable) {
         $isList = is_array($products) && array_keys($products) === range(0, count($products) - 1);
         $index = 0;
         $lastIndex = $isList ? count($products) - 1 : false;
         foreach ($products as $key => $var) {
             $specialVariables = array('@index' => $index, '@first' => $index === 0, '@last' => $index === $lastIndex);
             if (!$isList) {
                 $specialVariables['@key'] = $key;
             }
             $context->pushSpecialVariables($specialVariables);
             $context->push($var);
             $template->setStopToken('else');
             $template->rewind();
             $buffer .= $template->render($context);
             $context->pop();
             $context->popSpecialVariables();
             $index++;
         }
         $template->setStopToken(false);
     }
     return $buffer;
 }