Fix: In multi-select, selections do not appear in the order in which they were selected

@see https://github.com/select2/select2/issues/3106#issuecomment-339594053

@param \WP_Term[] $terms
@param array $value

@return array
357509
function _order_taxonomy_multi_select( array $terms, array $value ) {
		$ordered_terms = [];
		foreach ( $value as $slug ) {
			foreach ( $terms as $i => $term ) {
				if ( $term->slug === $slug ) {
					$ordered_terms[] = $term;
					unset( $terms[ $i ] );
					continue;
				}
			}
		}
		return array_merge( $ordered_terms, $terms );
	}
875031
public function set_terms( $terms = array(), $taxonomy = '', $append = false ) {
		return \wp_set_post_terms( $this->id(), $terms, $taxonomy, $append );
	}
400407
protected function persistRelatedEntities($value)
    {
        if (!is_array($value) && !$value instanceof \Iterator) {
            $value = [$value];
        }
        foreach ($value as $element) {
            if (is_object($element) && $element instanceof PersistenceMagicInterface) {
                $this->persistenceManager->isNewObject($element) ? $this->persistenceManager->add($element) : $this->persistenceManager->update($element);
            }
        }
    }
1060810
public function update(Term $term)
    {
        return wp_update_term($term->id, $this->getSlug(), (array) $term->getAdaptee());
    }
550476
public function filter($value)
    {
        // build search array
        $search = [
            '= |\(|\)|\/|\,|\'|´|\-|\_|`|\.|\@|\||&=',
            '=á|à|â|ã|ą|ă|ā|Â|Á|À|Ã|Ą|Ă|Ā=i',
            '=å|Å=i',
            '=ä|æ|Ä|Æ=i',
            '=ç|ć|č|ċ|ĉ|Ç|Ć|Č|Ċ|Ĉ=i',
            '=ď|Ď=i',
            '=ð|Ð=i',
            '=é|è|ê|ë|ę|ě|ē|ė|Ê|É|È|Ë|Ę|Ě|Ē|Ė=i',
            '=ğ|ġ|ĝ|ģ|Ğ|Ġ|Ĝ|Ģ=i',
            '=ħ|ĥ|Ħ|Ĥ=i',
            '=í|ì|î|ï|ı|ĩ|į|ï|Î|Í|Ì|Ï|İ|Ĩ|Į|Ī=i',
            '=ĵ|Ĵ=i',
            '=ķ|ĸ|Ķ=i',
            '=ł|ľ|ĺ|ļ|Ł|Ľ|Ĺ|Ļ=i',
            '=ñ|ń|ň|ņ|Ñ|Ń|Ň|Ņ=i',
            '=ó|ò|ô|õ|ő|ō|Ô|Ó|Ò|Õ|Ő|Ō=i',
            '=ö|ø|Ö|Ø=i',
            '=ŕ|ř|ŗ|Ŕ|Ř|Ŗ=i',
            '=š|ś|ş|ŝ|Š|Ś|Ş|Ŝ=i',
            '=ß=i',
            '=ť|ţ|ŧ|Ť|Ţ|Ŧ=i',
            '=Þ|þ=i',
            '=ú|ù|û|ů|ű|ŭ|ų|ũ|ū|Û|Ú|Ù|Ů|Ű|Ŭ|Ų|Ũ|Ū=i',
            '=ü|Ü=i',
            '=ý|ÿ|Ý|Ÿ=i',
            '=ź|ž|ż|Ź|Ž|Ż=i',
        ];

        // build replace array
        $replace = [
            $this->delimiter,
            'a',
            'aa',
            'ae',
            'c',
            'd',
            'dj',
            'e',
            'g',
            'h',
            'i',
            'j',
            'k',
            'l',
            'n',
            'o',
            'oe',
            'r',
            's',
            'ss',
            't',
            'th',
            'u',
            'ue',
            'y',
            'z',
        ];

        // replace special characters
        $value = preg_replace($search, $replace, (string)$value);

        // remove other characters
        $value = preg_replace(
            '=[^a-z0-9' . $this->delimiter . ']*=i', '', $value
        );

        // replace double delimiter
        $value = preg_replace(
            '=' . $this->delimiter . '+=', $this->delimiter, $value
        );

        // strip out leading and ending delimiter
        $value = preg_replace(
            '=^' . $this->delimiter . '|' . $this->delimiter . '$=', '',
            $value
        );

        // convert to lower case and return
        return strtolower($value);
    }
7394
protected function isValueSelected($value)
	{
		$val = $this->getValue();
		if (is_null($value)) {
			return FALSE;
		}
		elseif (is_array($val)) {
			return in_array($value, $val);
		}

		return $value == $val;
	}
652252
protected function _isMultilingualArray($value) {
        if (!is_array($value)) {
            return false;
        }
        $locales = Garp_I18n::getLocales();
        $keys = array_keys($value);
        sort($locales);
        sort($keys);

        return $locales === $keys;
    }
1156338
public function getSearchFilters($term)
    {
        $filters = [];
        
        foreach ($this->getSearchFields() as $field) {
            $filters[$this->getSearchFilterName($field)] = $term;
        }
        
        return $filters;
    }
1018121
public function createTaxables($terms, $taxonomy, $parent = 0, $order = 0)
    {
        $terms = TaxableUtils::makeTermsArray($terms);

        TaxableUtils::createTerms($terms);
        TaxableUtils::createTaxonomies($terms, $taxonomy, $parent, $order);
    }
244114
public function update( string $name, $value ) {
		if ( $this->term->$name ) {
			return wp_update_term( $this->term_id, $this->taxonomy, [
				$name => $value
			] );
		} elseif ( $this->$name ) {
			return update_field( $name, $value, $this->term );
		}
		
		return FALSE;
	}
522565
public function filter_by_term($term) {
        $this->where[] = sprintf("(%s = :filterterma OR %s = :filtertermb)",
            self::resolve_field('concept', 'entries'),
            self::resolve_field('alias', 'alias'));
        $this->params['filterterma'] = $term;
        $this->params['filtertermb'] = $term;
    }
43589
public function OrderBy($Value = NULL) {
      if ($Value === NULL)
         return $this->_OrderBy;

      if (is_string($Value))
         $Value = array($Value);

      if (is_array($Value)) {
         // Set the order of this object.
         $OrderBy = array();

         foreach($Value as $Part) {
            if (StringEndsWith($Part, ' desc', TRUE))
               $OrderBy[] = array(substr($Part, 0, -5), 'desc');
            elseif (StringEndsWith($Part, ' asc', TRUE))
               $OrderBy[] = array(substr($Part, 0, -4), 'asc');
            else
               $OrderBy[] = array($Part, 'asc');
         }
         $this->_OrderBy = $OrderBy;
      } elseif (is_a($Value, 'Gdn_SQLDriver')) {
         // Set the order of the given sql.
         foreach ($this->_OrderBy as $Parts) {
            $Value->OrderBy($Parts[0], $Parts[1]);
         }
      }
   }
1120240
public function setOrders($value)
    {
        if (!$this->_isNumericArray($value)) {
            $value = array ($value);
        }
        $this->_fields['Orders']['FieldValue'] = $value;
        return $this;
    }
457501
protected function checkSelected($value)
    {
        $value = (string) $value;

        if ($this->multiple) {
            return in_array($value, (array) $this->getSelected());
        } else {
            return $value == (string) $this->getSelected();
        }
    }
1329462
public function setValue($value) {
        global $DB;
        $values = (array) $value;
        $ids = array();

        foreach ($values as $onevalue) {
            if (!empty($onevalue) && (!$this->optionExists($onevalue)) &&
                    ($onevalue !== '_qf__force_multiselect_submission')) {
                array_push($ids, $onevalue);
            }
        }

        if (empty($ids)) {
            return $this->setSelected(array());
        }

        // Logic here is simulating API.
        $toselect = array();
        list($insql, $inparams) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED, 'param');
        $frameworks = competency_framework::get_records_select("id $insql", $inparams, 'shortname');
        foreach ($frameworks as $framework) {
            if (!has_any_capability(array('moodle/competency:competencyview', 'moodle/competency:competencymanage'),
                    $framework->get_context())) {
                continue;
            } else if ($this->onlyvisible && !$framework->get('visible')) {
                continue;
            }
            $this->addOption($framework->get('shortname') . ' ' . $framework->get('idnumber'), $framework->get('id'));
            array_push($toselect, $framework->get('id'));
        }

        return $this->setSelected($toselect);
    }
570168
public function termSave($value, int $term_id)
    {
        $this->setValue($value);

        $previous = get_term_meta($term_id, $this->getName(), true);

        if (is_null($this->getValue()) || empty($this->getValue())) {
            delete_term_meta($term_id, $this->getName());
        } elseif (empty($previous)) {
            add_term_meta($term_id, $this->getName(), $this->getRawValue(), true);
        } else {
            update_term_meta($term_id, $this->getName(), $this->getRawValue(), $previous);
        }
    }
562906
protected function getSelectedChoices(array $values, $value = null)
    {
        $structuredValues = $this->loadChoiceList($value)->getStructuredValues();
        $values = $this->forceStringValues($values);
        $allChoices = [];
        $choices = [];
        $isGrouped = false;

        foreach ($structuredValues as $group => $choice) {
            // group
            if (\is_array($choice)) {
                $isGrouped = true;
                foreach ($choice as $choiceKey => $choiceValue) {
                    if ($this->allChoices || \in_array($choiceValue, $values)) {
                        $choices[$group][$choiceKey] = $choiceValue;
                        $allChoices[$choiceKey] = $choiceValue;
                    }
                }
            } elseif ($this->allChoices || \in_array($choice, $values)) {
                $choices[$group] = $choice;
                $allChoices[$group] = $choice;
            }
        }

        if ($this->isAllowAdd()) {
            $choices = $this->addNewTagsInChoices($choices, $allChoices, $values, $isGrouped);
        }

        return (array) $choices;
    }