# Prevent a user to create two identical items in a structure field

**URL:** <https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511>\
**Category:** Questions\
**Tags:** v3\
**Created:** [December 1, 2019, 1:25pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511 "2019-12-01T13:25:29Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![gillesvauvarin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/gillesvauvarin/32/2351_2.png) [@gillesvauvarin](https://forum.getkirby.com/u/gillesvauvarin)\
**Post date:** [December 1, 2019, 1:25pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/1 "2019-12-01T13:25:30Z")

</div>

Hello,

I would like to prevent a user to create two identical items in a structure field. My structure field has a simple text field.

I’ve made a function to check if a multidimensional array has two identical values:

```auto
function search_identical_value( $array , $field ) {
    $flag = false;
    foreach ( $array as $current_key => $current_array ) {
        foreach ( $array as $search_key => $search_array ) {
            if ( $search_array[$field] == $current_array[$field]) {
                if ( $search_key != $current_key ) {
                    $flag = true;
                    break;
                }
            }
        }
        if ( $flag ) {
            break;
        }
    }
    return $flag;
}

```

This function works well and return true if two identical items has been found. I put this function in the plugin folder to be accessible from the config file.

This is my blueprint

```auto
fields:
      questions:
        label: Questions or instructions
        help: Start your question or instruction with a numbering
        type: structure
        fields:
          questionsLabel:
            label: Question
            type: textarea
            default: '1- ... (Start your question or instruction with a numbering)'
            required: true

```

To check and prevent two identical items in my structure field, I put this in my config file:

```auto
return [
    'debug' => true,

    'hooks' => [

	    'page.update:after' => function ( $newPage, $oldPage ) {

	            $questions = array();
	            $questions = $newPage->questions()->yaml();

	            if ( search_identical_value( $questions , 'questionslabel' ) ) :
	                throw new Exception('Check your questions, you cannot create two identical questions.');
	            endif;
	    },

	]
];

```

The Exception pop-up if I create two identical items but when I delete the second item from the structure field, the save orange bar disappears and the two items stay in the txt file. So if I reload my panel page, the two items are visible.

Any idea how I can avoid this?

You can test with this starter kit \> go to the about page, the structure field is below the textarea. (delete the account folder to reinstall a new admin user)  
[https://www.swisstransfer.com/d/0ee35c75-7d0d-4fef-8072-09a232f694b0](https://www.swisstransfer.com/d/0ee35c75-7d0d-4fef-8072-09a232f694b0)

Thx

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [December 1, 2019, 1:35pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/2 "2019-12-01T13:35:31Z")

</div>

I think a `page.update:before` hook would be more appropriate, but I’ll test with your example.

---

<div class="post-metadata">

**Author:** ![gillesvauvarin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/gillesvauvarin/32/2351_2.png) [@gillesvauvarin](https://forum.getkirby.com/u/gillesvauvarin)\
**Post date:** [December 1, 2019, 1:37pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/3 "2019-12-01T13:37:18Z")

</div>

I did some test with page.update:before but without success:

```auto
return [
    'debug' => true,

    'hooks' => [

	    'page.update:before' => function ( $page, $values, $strings ) {

	            $questions = array();
	            $questions = $page->questions()->yaml();

	            if ( search_identical_value( $questions , 'questionslabel' ) ) :
	                throw new Exception('Check your questions, you cannot create two identical questions.');
	            endif;
	    },

	]
];

```

PS: I don’t really understand what the parameters $values and $strings contain exactly?

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [December 1, 2019, 1:50pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/4 "2019-12-01T13:50:26Z")

</div>

Hm, yes, you are right, neither option works as expected.

And why don’t you remove duplicate items from the array instead of throwing an error message?

The problem is that throwing the error actually prevents the action from being executed. So the duplicate entry is not stored and so if you remove the item again, there is no difference to before, so no orange bar (unless there are more changes than a single added duplicate item).

With your default entry to make it very likely that duplicate entries happen in the first place.

---

<div class="post-metadata">

**Author:** ![gillesvauvarin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/gillesvauvarin/32/2351_2.png) [@gillesvauvarin](https://forum.getkirby.com/u/gillesvauvarin)\
**Post date:** [December 1, 2019, 2:19pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/5 "2019-12-01T14:19:46Z")

</div>

I use the Exception pop-up because I want to inform the user that he/she has created two identical items and he/she can’t do this.

---

<div class="post-metadata">

**Author:** ![gillesvauvarin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/gillesvauvarin/32/2351_2.png) [@gillesvauvarin](https://forum.getkirby.com/u/gillesvauvarin)\
**Post date:** [December 1, 2019, 2:27pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/6 "2019-12-01T14:27:06Z")

</div>

> [@texnixe](#):
>
> throwing the error actually prevents the action from being executed

Not sure to understand, why the two identical items are written in the txt file if the action is not executed?

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [December 1, 2019, 2:28pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/7 "2019-12-01T14:28:44Z")

</div>

Sorry, I was talking nonsense.

---

<div class="post-metadata">

**Author:** ![gillesvauvarin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/gillesvauvarin/32/2351_2.png) [@gillesvauvarin](https://forum.getkirby.com/u/gillesvauvarin)\
**Post date:** [December 1, 2019, 2:29pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/8 "2019-12-01T14:29:32Z")

</div>

😉

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [December 1, 2019, 2:36pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/9 "2019-12-01T14:36:57Z")

</div>

Yes, the changes are saved but the orange bar doesn’t disappear after clicking ok in the pop-up. So I assume the content store and what is actually stored in the file are out of sync at this time.

---

<div class="post-metadata">

**Author:** ![gillesvauvarin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/gillesvauvarin/32/2351_2.png) [@gillesvauvarin](https://forum.getkirby.com/u/gillesvauvarin)\
**Post date:** [December 1, 2019, 3:21pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/10 "2019-12-01T15:21:49Z")

</div>

So as you suggested above, the solution would be to delete the duplicate value in the array and update my structure field with the new array state, then throw the error to inform the user 🤔

I will try to do some test …

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [December 1, 2019, 3:24pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/11 "2019-12-01T15:24:14Z")

</div>

> [@gillesvauvarin](#):
>
> then throw the error to inform the user

Or tell the user in the help text that this is what will happen without throwing the error.

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [December 1, 2019, 4:12pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/12 "2019-12-01T16:12:14Z")

</div>

On a side note, you could simplify your logic:

```auto
<?php 

$questions = A::pluck(page('about')->questions()->yaml(), 'questionslabel');
$unique = array_unique($questions);

if (count($questions) !== count($unique)) {
  echo "There are duplicate entries";
}
?>

```

Which has the additional advantage that you can store `$unique` as your new value.

But what if your users use different numbers but the same questionlabel? Wouldn’t it make more sense to leave the numbers out and only add them in the template. Or if they by mistake use the same number for a different questionlabel? Then your check will find that they are different but they will still come out wrong on the frontend.

---

<div class="post-metadata">

**Author:** ![gillesvauvarin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/gillesvauvarin/32/2351_2.png) [@gillesvauvarin](https://forum.getkirby.com/u/gillesvauvarin)\
**Post date:** [December 1, 2019, 4:28pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/13 "2019-12-01T16:28:41Z")

</div>

Thanks Sonja, it’s an interesting shorten solution.

I ask for the numbering because there was a bug with the sortBy options, but I think the last version has fixed this bug, so maybe I don’t need to ask the user to numbering there questions anymore.

---

<div class="post-metadata">

**Author:** ![felixbridell](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/felixbridell/32/6626_2.png) [@felixbridell](https://forum.getkirby.com/u/felixbridell)\
**Post date:** [January 17, 2020, 11:56am UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/14 "2020-01-17T11:56:41Z")

</div>

Did you manage to sort this out? I’m current looking for a similar solution and wonder if you have any code you can share?

---

<div class="post-metadata">

**Author:** ![felixbridell](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/felixbridell/32/6626_2.png) [@felixbridell](https://forum.getkirby.com/u/felixbridell)\
**Post date:** [January 31, 2020, 9:23am UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/15 "2020-01-31T09:23:30Z")

</div>

@texnixe I’m trying to implement a similar function to the panel by following the function you wrote about here: [Structure field update](https://forum.getkirby.com/t/structure-field-update/7854)  
But I can’t get i to work.

My function looks like this:

```auto
function addToStructure($pageURI, $field, $data = array()) {
  kirby()->impersonate('kirby');
  $fieldData = page($pageURI)->$field()->yaml();
  $fieldData[] = $data;
  $fieldData = yaml::encode($fieldData);
  try {
    page($pageURI)->update(array(
      $field => $fieldData
      )
    );
    return true;
  } catch(Exception $e) {
    return $e->getMessage();
  }
}

```

And my hook like this:

```auto
'page.update:before' => function ($page, $values, $strings) {

    if ($page == page('tag-manager')):
      $globalTags = A::pluck($page->global_tags()->yaml(), 'tag');
      $unique = array_unique($globalTags);

      if (count($globalTags) !== count($unique)):
        // There are duplicate entries
        addToStructure($pageURI = 'tag-manager', $field = 'global_tags', $data = $unique);
      endif;
    endif;
  }

```

And the blueprint with the structure field looks like this:

```auto
tags_section:
  type: fields
  fields:
    global_tags:
      label: Globala taggar
      type: structure
      sortBy: tag asc
      fields:
        tag:
          label: Tag
          type: text

```

If I enter two identical values to the structure field from the panel and hit save, the data is just saved, and the duplicates are still there. I’m using Kirby v3.2.3

What am I missing?

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [January 31, 2020, 10:32am UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/16 "2020-01-31T10:32:59Z")

</div>

@felixbridell I’ll look into that later, don’t have time now.

---

<div class="post-metadata">

**Author:** ![felixbridell](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/felixbridell/32/6626_2.png) [@felixbridell](https://forum.getkirby.com/u/felixbridell)\
**Post date:** [January 31, 2020, 10:50am UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/17 "2020-01-31T10:50:03Z")

</div>

You are so kind. Thank you.

I got i working if I run the function from a page but still not from the panel via the hook.

I changed the function to this:

```auto
function addToStructure($pageURI, $field, $data = array()) {
  kirby()->impersonate('kirby');
  $fieldData = yaml::encode($data);

  try {
    page($pageURI)->update(array(
      $field => $fieldData
      )
    );
    return true;
  } catch(Exception $e) {
    return $e->getMessage();
  }
}

```

And the hook to this:

```auto
'page.update:before' => function ($page, $values, $strings) {

    if ($page == page('tag-manager')):
      $globalTags = A::pluck($page->global_tags()->yaml(), 'tag');
      $unique = array_values(array_unique($globalTags));

      if (count($globalTags) !== count($unique)):
        // There are duplicate entries
        $uniqueTags = [];
        foreach ($unique as $tag) {
          $uniqueTags[] = [
            'tag' => $tag
          ];
        }
        
        addToStructure($pageURI = 'tag-manager', $field = 'global_tags', $data = $unique);
      endif;
    endif;
  }

```

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [January 31, 2020, 11:08am UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/18 "2020-01-31T11:08:35Z")

</div>

I think the problem is that you are trying to do this from a before hook?

---

<div class="post-metadata">

**Author:** ![felixbridell](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/felixbridell/32/6626_2.png) [@felixbridell](https://forum.getkirby.com/u/felixbridell)\
**Post date:** [January 31, 2020, 11:40am UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/19 "2020-01-31T11:40:11Z")

</div>

If I change

```auto
'page.update:before' => function ($page, $values, $strings) {

```

to

```auto
'page.update:after' => function ($page, $values, $strings) {

```

I get this error from panel:  
Exception: ArgumentCountError  
Too few arguments to function Kirby\Cms\App::{closure}(), 2 passed and exactly 3 expected.

And If I change to:

```auto
'page.update:after' => function ($page) {

```

Nothing happen on save…

---

<div class="post-metadata">

**Author:** ![texnixe](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.getkirby.com/texnixe/32/5754_2.png) [@texnixe](https://forum.getkirby.com/u/texnixe)\
**Post date:** [January 31, 2020, 12:33pm UTC](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511/20 "2020-01-31T12:33:58Z")

</div>

This works

```auto

    'hooks' => [
        'page.update:after' => function ($page) {

            if ($page == page('tag-manager')):
              $globalTags = A::pluck($page->global_tags()->yaml(), 'tag');
              $unique = array_values(array_unique($globalTags));
        
              if (count($globalTags) !== count($unique)):
                // There are duplicate entries
                $uniqueTags = [];
                foreach ($unique as $tag) {
                  $uniqueTags[] = [
                    'tag' => $tag
                  ];
                }
                
                addToStructure('tag-manager', 'global_tags', $uniqueTags);
              endif;
            endif;
          },
    ]

```

Note that I changed the array you passed to the `addToStructure()` method.  
But note the changes the hook makes will only be visible in the Panel if you reload the page.

[Next page](https://forum.getkirby.com/t/prevent-a-user-to-create-two-identical-items-in-a-structure-field/16511.md?page=2)
