<p>Something like this should work:</p>

<pre><code>{% set listItems = plainTextValue|replace('/[^, a-zA-Z0-9_-]|[, ]$/s','')|split(',') %}

&lt;ul&gt;
  {% for listItem in listItems %}
    {% if listItem|length %}
      &lt;li&gt;{{ listItem|trim }}&lt;/li&gt;
    {% endif %}
  {% endfor %}
&lt;/ul&gt;
</code></pre>

<p>What the above does is to first use the <a href="https://craftcms.com/docs/templating/filters#replace" rel="nofollow"><code>replace</code></a> filter to remove any character that isn't alphanumeric (except spaces and commas), before the resulting string (which would look something like <code>'Abdominal Pain,RUQ,Vomiting'</code>) is split on the commas. The resulting array is stored in a variable <code>listItems</code>. Finally, it's just a matter of looping through that array, to create the <code>&lt;li&gt;</code> items.</p>

<p>Note that in the above example, <code>plainTextValue</code> is a variable containing the string <code>'["Abdominal Pain","RUQ","Vomiting",""]'</code> – so swap that out with <code>entry.logGeneral_logInputIndications</code>, or whatever fits.</p>

<p><strong>Edit (OP added more info to the original question)</strong></p>

<p>If your "symptoms" are in fact <em>hierarchical</em>, I'd suggest not using a PlainText field at all. You're quickly running into a situation where your back-end solution is way too simple, which will make your front-end solution way too complex.</p>

<p>My definitive recommendation would be to create a Categories group for the symptoms, and swap out the PlainText field for a Categories field.</p>

<p>Note that you can still render the actual symptoms form element on the front end as checkboxes, you'd just pass in an array of category IDs instead of a plain text string (the following example assumes a Categories group with the handle <code>symptoms</code> and a Categories field with the handle <code>selectedSymptoms</code>):</p>

<pre><code>{# Get all available symptoms #}
{% set symptoms = craft.categories.group('symptoms').limit(null) %}

{# Get the symptoms that have been selected for this entry earlier #}
{% set selectedSymptoms = entry.selectedSymptoms.ids() %}

{# Loop through the available symptoms, creating checkboxes #}
{% for symptom in symptoms %}
    &lt;input type="checkbox" name="fields[selectedSymptoms][]" value="{{ symptom.id }}"{% if symptom.id in selectedSymptoms %} checked{% endif %} /&gt;{{ symptom.title }}&lt;br /&gt;
{% endfor %}
</code></pre>

<p>...and to display whatever symptoms are already selected – in nested lists, as per the category hiearchy, you can use the <a href="https://craftcms.com/docs/templating/nav" rel="nofollow"><code>{% nav %}</code></a> tag:</p>

<pre><code>&lt;ul&gt;
{% nav symptom in entry.selectedSymptoms %}
    &lt;li&gt;
        {{ symptom.title }}
        {% ifchildren %}
            &lt;ul&gt;
                {% children %}
            &lt;/ul&gt;
        {% endifchildren %}
    &lt;/li&gt;
{% endnav %}
&lt;/ul&gt;
</code></pre>

CC BY-SA 3.0
2016-09-21T19:32:40.263Z
Your suggestion worked perfectly @Mats thank you!  I just realized that I have checkbox choices that contain non-alphanumeric content like `Normal CBD (<0.4cm)`  Is there a way to pick and choose which non-alphanumeric content I'd like to strip out vs keep?  Also, I edited my initial content with another layer to the question. I wasn't sure if what I was trying to do was possible therefore I didn't want to add more complexity to my question initially. I hope this is okay to add to my initial question.
Lori
CC BY-SA 3.0
2016-09-21T20:07:16.330Z
Yes, you can add any additional characters you want to keep to the regular expression, e.g. if you want to keep `(`, `)` and `<` you would write `'/[^,()< a-zA-Z0-9_-]|[, ]$/s'` (notice the extra characters after the `^`).
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2016-09-21T20:24:43.380Z
However, I don't think you're on the right track if the symptoms are hierarchical/nested, see my edited answer above :)
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2016-09-21T18:52:11.213Z
2016-09-21T20:30:04.377Z
2016-09-21T20:30:04.377Z
Mats Mikkel Rummelhoff
<p>Is the data a pseudo-syntax, or is it JSON?</p>

<p>If the answer is JSON, then the following may be a more robust solution:</p>

<ol>
<li><p>Create a barebones plugin (<code>craft/plugins/helpers/HelpersPlugin.php</code>)</p>

<pre><code>&lt;? namespace Craft;

class HelpersPlugin extends BasePlugin
{
  public function getName()
  {
    return Craft::t('Helpers');
  }

  public function getVersion()
  {
    return '1.0';
  }

  public function getDeveloper()
  {
    return 'Your Name';
  }

  public function getDeveloperUrl()
  {
    return 'http://domain.com/';
  }

  public function hasCpSection()
  {
    return false;
  }
}
</code></pre></li>
<li><p>Add the class that will get loaded as a set of helpers within your templates: (<code>craft/plugins/helpers/variables/HelpersVariable.php</code>)</p>

<pre><code>&lt;? namespace Craft;

class HelpersVariable
{
  public function parseSymptoms(String $json)
  {
    return array_filter(json_decode($json));
  }
}
</code></pre></li>
<li><p>Use the helper like this: (<code>craft/templates/your-template.twig</code>)</p>

<pre><code>&lt;ul&gt;
  {% for ailment in craft.helpers.parseSymptoms(entry.logGeneral_logInputIndications) %}
    &lt;li&gt;{{ ailment }}&lt;/li&gt;
  {% endfor %}
&lt;/ul&gt;
</code></pre></li>
</ol>

<p>You could add methods to the <code>HelpersVariable</code> class do additional checks— you'll be able to use the full range of PHP methods to manipulate the data, rather than rely on the subset of functions available as Twig filters.</p>

CC BY-SA 3.0
2016-09-21T19:20:16.060Z
Thank you for your response, August.  I hate to say this, but I'm afraid your answer is way over my head. I have a front end form with checkboxes and instead of using the checkbox Craft field I used a plain text field for a few different reasons.  I really appreciate you taking the time to send a suggestion and hopefully your suggestion will help others who have more development skill than I do ;)
Lori
CC BY-SA 3.0
2016-09-22T19:02:28.400Z
Hey! No sweat— I was (admittedly) answering a question that wasn't really being asked. A bit of context: If the text stored in your field _is_ JSON, you should be using a native parser, not Regex. As you discovered, above, there will always be breaking exceptions to what characters are allowed in a symptom, but if the stored value obeys an existing syntax like JSON, you can reliably expand it back into usable values with this plugin method. Best of luck!
August Miller
CC BY-SA 3.0
2016-09-21T19:16:19.100Z
2016-09-21T19:16:19.100Z
August Miller
<p>I have a front end form with checkboxes which submits the data as an array into a plain text field in craft (named <code>logGeneral_logInputIndications</code>). </p>

<p>Here's an example of what the content looks in the plain text field in Craft CP:</p>

<pre><code>["Abdominal Pain","RUQ","Vomiting",""]
</code></pre>

<p>Instead of outputting the field content in it's default state into my template, I'd like to convert it to an unordered list.  If I were to code it by hand it would look like this:</p>

<pre><code>&lt;ul&gt;
    &lt;li&gt;Abdominal Pain&lt;/li&gt;
    &lt;li&gt;RUQ&lt;/li&gt;
    &lt;li&gt;Vomiting&lt;/li&gt;
&lt;/ul&gt;
</code></pre>

<p>Any ideas if it's possible to do this?</p>

<p><strong>(Mats answered the above question and his suggestion worked perfectly.)</strong></p>

<p>However, I just realized that I have checkbox choices that contain non-alphanumeric content like <code>Normal CBD (&lt;0.4cm)</code>  Is there a way to pick and choose which non-alphanumeric content I'd like to strip out vs keep?</p>

<p><strong>Here's a new question that builds upon my initial one...</strong></p>

<p>Is it possible to add a conditional to this?  Some of the text is really a child so it should be inset by another unordered list.  What my initial thought was is that perhaps I could add an identifier to the form input text if it's a child like "•" or something else, and then in the template, use that identifier in a conditional to say if you see "•" indent it and then strip the marker "•".</p>

<p>So then my plain text content would be: </p>

<pre><code>["Abdominal Pain","•RUQ","Vomiting",""]
</code></pre>

<p>And my template code would look like this:</p>

<pre><code>&lt;ul&gt;
    &lt;li&gt;Abdominal Pain&lt;/li&gt;
    &lt;ul&gt;
        &lt;li&gt;RUQ&lt;/li&gt;
    &lt;ul&gt;
    &lt;li&gt;Vomiting&lt;/li&gt;
&lt;/ul&gt;
</code></pre>

<p><strong>I was able to combine the suggestion Mats gave me with the following to conditionally indent child items.</strong></p>

<pre><code>{% set listItems = entry.logGeneral_logInputIndications|replace('/[^,()&lt;&gt;• a-zA-Z0-9_-]|[, ]$/s','')|split(',') %}
&lt;ul&gt;
    {% if entry.logGeneral_logInputIndications|length %}
        {% for listItem in listItems %}
            {% if listItem starts with '•' %}
                &lt;ul&gt;&lt;li&gt;{{ listItem|trim|slice(1) }}&lt;/li&gt;&lt;/ul&gt;
            {% else %}
                &lt;li&gt;{{ listItem|trim }}&lt;/li&gt;
            {% endif %}
        {% endfor %}
    {% endif %}
&lt;/ul&gt;
</code></pre>

<templating><array><checkboxes>
Is it possible to convert plain text array to an unordered list?
# Is it possible to convert plain text array to an unordered list?

(Asked by: username_0 on 2016-09-21)

I have a front end form with checkboxes which submits the data as an array into a plain text field in craft (named logGeneral_logInputIndications). 
Here's an example of what the content looks in the plain text field in Craft CP:
["Abdominal Pain","RUQ","Vomiting",""]

Instead of outputting the field content in it's default state into my template, I'd like to convert it to an unordered list.  If I were to code it by hand it would look like this:

    Abdominal Pain
    RUQ
    Vomiting


Any ideas if it's possible to do this?
(Mats answered the above question and his suggestion worked perfectly.)
However, I just realized that I have checkbox choices that contain non-alphanumeric content like Normal CBD (<0.4cm)  Is there a way to pick and choose which non-alphanumeric content I'd like to strip out vs keep?
Here's a new question that builds upon my initial one...
Is it possible to add a conditional to this?  Some of the text is really a child so it should be inset by another unordered list.  What my initial thought was is that perhaps I could add an identifier to the form input text if it's a child like "•" or something else, and then in the template, use that identifier in a conditional to say if you see "•" indent it and then strip the marker "•".
So then my plain text content would be: 
["Abdominal Pain","•RUQ","Vomiting",""]

And my template code would look like this:

    Abdominal Pain
    
        RUQ
    
    Vomiting


I was able to combine the suggestion Mats gave me with the following to conditionally indent child items.
{% set listItems = entry.logGeneral_logInputIndications|replace('/[^,()<>• a-zA-Z0-9_-]|[, ]$/s','')|split(',') %}

    {% if entry.logGeneral_logInputIndications|length %}
        {% for listItem in listItems %}
            {% if listItem starts with '•' %}
                {{ listItem|trim|slice(1) }}
            {% else %}
                {{ listItem|trim }}
            {% endif %}
        {% endfor %}
    {% endif %}

**Tags:** templating, array, checkboxes


---

## 2 answers

### Answer by username_1 on 2016-09-21. Score: 2 | Accepted answer

Something like this should work:
{% set listItems = plainTextValue|replace('/[^, a-zA-Z0-9_-]|[, ]$/s','')|split(',') %}


  {% for listItem in listItems %}
    {% if listItem|length %}
      {{ listItem|trim }}
    {% endif %}
  {% endfor %}


What the above does is to first use the replace filter to remove any character that isn't alphanumeric (except spaces and commas), before the resulting string (which would look something like 'Abdominal Pain,RUQ,Vomiting') is split on the commas. The resulting array is stored in a variable listItems. Finally, it's just a matter of looping through that array, to create the  items.
Note that in the above example, plainTextValue is a variable containing the string '["Abdominal Pain","RUQ","Vomiting",""]' – so swap that out with entry.logGeneral_logInputIndications, or whatever fits.
Edit (OP added more info to the original question)
If your "symptoms" are in fact hierarchical, I'd suggest not using a PlainText field at all. You're quickly running into a situation where your back-end solution is way too simple, which will make your front-end solution way too complex.
My definitive recommendation would be to create a Categories group for the symptoms, and swap out the PlainText field for a Categories field.
Note that you can still render the actual symptoms form element on the front end as checkboxes, you'd just pass in an array of category IDs instead of a plain text string (the following example assumes a Categories group with the handle symptoms and a Categories field with the handle selectedSymptoms):
{# Get all available symptoms #}
{% set symptoms = craft.categories.group('symptoms').limit(null) %}

{# Get the symptoms that have been selected for this entry earlier #}
{% set selectedSymptoms = entry.selectedSymptoms.ids() %}

{# Loop through the available symptoms, creating checkboxes #}
{% for symptom in symptoms %}
    {{ symptom.title }}
{% endfor %}

...and to display whatever symptoms are already selected – in nested lists, as per the category hiearchy, you can use the {% nav %} tag:

{% nav symptom in entry.selectedSymptoms %}
    
        {{ symptom.title }}
        {% ifchildren %}
            
                {% children %}
            
        {% endifchildren %}
    
{% endnav %}

> **Comments:**
> **username_0**: Your suggestion worked perfectly @Mats thank you!  I just realized that I have checkbox choices that contain non-alphanumeric content like `Normal CBD (<0.4cm)`  Is there a way to pick and choose which non-alphanumeric content I'd like to strip out vs keep?  Also, I edited my initial content with another layer to the question. I wasn't sure if what I was trying to do was possible therefore I didn't want to add more complexity to my question initially. I hope this is okay to add to my initial question.  
> **username_1**: Yes, you can add any additional characters you want to keep to the regular expression, e.g. if you want to keep `(`, `)` and `<` you would write `'/[^,()< a-zA-Z0-9_-]|[, ]$/s'` (notice the extra characters after the `^`).  
> **username_1**: However, I don't think you're on the right track if the symptoms are hierarchical/nested, see my edited answer above :)  

---

### Answer by username_2 on 2016-09-21. Score: 2

Is the data a pseudo-syntax, or is it JSON?
If the answer is JSON, then the following may be a more robust solution:

Create a barebones plugin (craft/plugins/helpers/HelpersPlugin.php)

Add the class that will get loaded as a set of helpers within your templates: (craft/plugins/helpers/variables/HelpersVariable.php)

Use the helper like this: (craft/templates/your-template.twig)

  {% for ailment in craft.helpers.parseSymptoms(entry.logGeneral_logInputIndications) %}
    {{ ailment }}
  {% endfor %}



You could add methods to the HelpersVariable class do additional checks— you'll be able to use the full range of PHP methods to manipulate the data, rather than rely on the subset of functions available as Twig filters.

> **Comments:**
> **username_0**: Thank you for your response, August.  I hate to say this, but I'm afraid your answer is way over my head. I have a front end form with checkboxes and instead of using the checkbox Craft field I used a plain text field for a few different reasons.  I really appreciate you taking the time to send a suggestion and hopefully your suggestion will help others who have more development skill than I do ;)  
> **username_2**: Hey! No sweat— I was (admittedly) answering a question that wasn't really being asked. A bit of context: If the text stored in your field _is_ JSON, you should be using a native parser, not Regex. As you discovered, above, there will always be breaking exceptions to what characters are allowed in a symptom, but if the stored value obeys an existing syntax like JSON, you can reliably expand it back into usable values with this plugin method. Best of luck!  

---

