phperがShopify Liquid言語のシンタックスをまとめてみました。

PHPでよく使うシンタックスがliquid言語に変換したらどうなるのかをまとめてみました。liquid関連の案件を手伝う際にすぐ脳内変換できるようにこちらの記事を書きました。

### 変数をHTMLへの出力

```php
# PHP
<?= $myVar ?>

{% comment %} liquid {% endcomment %}
{{ myVar }}
```

### Liquid言語の始まりと終わり。

ただし、PHPと違って、１つの処理しかできないシンタックスと改行して複数の処理をするシンタックスが違います。

１つの処理のみの記述

```php
<?php $myVar = 1; ?>

{% comment %} liquid {% endcomment %}
{% assign myVar = 1 %}
```

２つ以上の処理の記述

```php
<?php $myVar = 1; echo $myVar; ?>

{% comment %} liquid (1) {% endcomment %}
{% liquid 
assign myVar = 1 
echo myVar
%}

{% comment %} liquid (2) {% endcomment %}
{% assign myVar = 1 %}
{% echo myVar %}
```

### if 分 else 分

```php
<?php 
if ($myVar == 1) { 
    echo $doSomethingA;
} else if ($myVar != 2) {
    echo $doSomethingB;
} else {
    echo $doSomethingC;
}
?>

{% comment %} liquid {% endcomment %}
{% liquid
if $myVar == 1
    echo doSomethingA
elsif $myVar != 2
    echo doSomethingB
else
    echo doSomethingC
endif
%}
```

if分の反転

```php
<?php
if (! $myVar) {
   echo $doSomethingA;
}
?>

{% comment %} 
liquid
PHPのように ! (びっくりマーク)のシンタックスが存在していないため
反転処理の場合は unless を使う
{% endcomment %}
{% unless myVar %}
   {{ doSomethingA }}
{% endunless %}
```

[https://shopify.dev/api/liquid/tags#if](https://shopify.dev/api/liquid/tags#if)

[https://shopify.dev/api/liquid/basics#operators](https://shopify.dev/api/liquid/basics#operators)

### 文字列の結合文字列の検索

```php
<?php 
$myVar = "Hello World";
if (strpos($myVar, "Hello") !== false) {
    echo "It is true";
}
?>

{% comment %} liquid {% endcomment %}
{% liquid
assign myVar = "Hello World"
if myVar contains "Hello"
   echo "It is true"
endif 
%}
```

### 足し算、引き算、割り算、掛け算

```php
<?php $myVar = 1 + 1 - 1 / 5 * 5; ?>

{% comment %} liquid {% endcomment %}
{% assign myVar = 1 | sum: 1 | minus: 1 | divided_by: 5 | times: 5 %}
```

[https://shopify.dev/api/liquid/filters#math-filters](https://shopify.dev/api/liquid/filters#math-filters)

### 配列操作 (1) - 配列の定義、初期化

```php
<?php $myarr = [1,2,3]; ?>

{% comment %} 
liquid 
仕様のため、定義および初期化ができない。ただし、文字列からsplitしてhackすることが可能。ここで注意すべき点としてsplit後の値が数字ではなくて、文字列であること。
{% endcomment %}
{% assign myarr = "1,2,3" | split: "," %}
```

### 配列操作 (2) - ループ

```php
<?php  
foreach ($myarr as $num) {
   echo $num;
}
?>

{% comment %} liquid {% endcomment %}
{% liquid
for num in myarr
  echo num
endfor
%}
```

### 配列操作 (2) - マッピング

```php
<?php
$itemNames = array_map(function($item) {
    return $item->title;
}, $cart->items);

?>

{% comment %} liquid {% endcomment %}
{% itemNames = cart.items | map: 'title' %}
```

liquidのmapメソッドはobjectから値を抽出する以外のことができない。例えば、次のような数学の変換や文字列の結合などができない。

```php
<?php

# できない例１
$mappedArr = array_map(function($num) {
    return $num * 5;
}, $myarr);

# できない例２
$mappedArr = array_map(function($item) {
    return "¥" . number_format($item->price);
}, $carts);

?>
```

### 配列操作 (3) - 配列から検索

```php
<?php 
$myarr = ["1","2","3"];
if (in_array($myarr, "1")) {
   echo "It is true";
} 
?>

{% liquid
assign myarr = "1,2,3" | split: ","
if myarr contains "1"
   echo "It is true"
endif
%}
```

予約語のcontains は文字列の検索と配列の検索両方に使えます。

### コンポーネントのインクルメント、引用

```php
<?php include "product.php"; ?>

{% comment %} liquid {% endcomment %}
{% render "product" %}
```

### 関数

```php
<?php
function sumFunc($arg1, $arg2) {
  return $arg1 + $arg2;
}
$result = sumFunc($arg1, $arg2);
?>

{% comment %} 
liquid 
仕様のため、関数を定義することが不可です。ただし、captureとrenderを
ハックすることで次のように実装することができる。
{% endcomment %}
```

sumFunc.liquidファイルでsumFunc関数を定義します。

```php
{%- liquid
assign result = arg1 | sum: arg2
echo result
-%}
```

sumFuncを呼び出し、実行し、result変数に実行結果を格納します。

```php
{% capture "result" %}
  {%- render "sumFunc", arg1: arg1, arg2: arg2 | trim -%}
{% endcapture %}
```

### 応用編 (1) - 消費税込と税抜きのロジック

税込み→税抜き

```jsx
<?php $excludeTax = floor($includeTax / 110 * 100); ?>

{% assign excludeTax = includeTax | divided_by: 110 | times: 100 | floor %}
```

税抜き→税込み

```jsx
<?php $includeTax = floor($excludeTax * 110 / 100); ?>

{% assign excludeTax = includeTax | times: 110 | divided_by: 100 | floor %}
```

### 応用編 (2) - whitespaceコントロール

phpにない機能ですが、コードを整形してindentでうまれたホワイトスペースを消すことが可能です。

captureを使うと格納される文字列の変数に前後が大量のスペースが生まれてしまう可能性があります。そこでwhitespace コントロールを使うと便利です。

```jsx
{% capture "myVar" %}
  {% echo "Hello world" %}
{% endcapture %}

{% comment %}
myVarの値は "  Hello world  " になる。改行および前後にスペースが入ってします
{% endcomment %}
```

ただし、 `{%-` liquidタグにマイナスを加えると前後のスペースを消すことができます。

```php
{% capture "myVar" %}
  {%- echo "Hello world" -%}
{% endcapture %}

{% comment %}
myVarの値は "Hello world" になる。改行および前後のスペースが消える。
{% endcomment %}
```

### 応用編 (3) - Shopifyのメタフィールド

shopifyの商品ページで最も自由度の高い表記機能です。商品に関するさらなる詳細の情報がメタフィールドを使うことで実現できます。メタフィールドはテキスト、画像、リンク情報だけではなくて、関連商品や、おすすめ商品、サイズ、形状、カラーなどの情報も載せられます。

管理画面での設定はこんな感じです。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60849/91705113-5d38-b7e8-948f-53e4ec18a712.png)

メタフィールドの値は単一または複数の２パターンがあります。上記の例では、次のように定義することで値を表示することができます。

```php
{% comment %} 単一の場合は {% endcomment %}
Weight: {{ product.metafields.my_fields.package_weight }}

{% comment %} 複数の場合は最後に list を加えた上でfor分でループすることができます。 {% endcomment %}
<ul>
  {% for item in product.metafields.descriptors.care_guide.list %}
  <li>{{ item }}</li>
  {% endfor %}
</ul>
```

ただし、配列の場合はそのまま

[https://help.shopify.com/ja/manual/metafields](https://help.shopify.com/ja/manual/metafields)

### 補足 - liquidのplayground

Liquid言語を軽く触ってみる公式playgroundがありませんが、liquid.jsという非公式のサイトがあるので手元にshopifyの環境がなくてもオンラインで簡易なliquid のデバッグが可能です。

[https://liquidjs.com/playground.html](https://liquidjs.com/playground.html)

### 参考ソース

- [https://www.shopify.com/partners/shopify-cheat-sheet](https://www.shopify.com/partners/shopify-cheat-sheet)