3

In Craft 3, I've got a service function that I'm passing either an 'entry' or 'category' element into.

I'd like to know how to differentiate between the possible element types; This kinda of works:

public function getElementType($element) {
  if ( isset($element->group) ) {
    return = 'category';
  } else if (isset($element->section)) {
    return = 'entry';        
  }
}

However I can't help but feel this is unreliable and hacky. Is there a better way to check an elements elementType?

6 Answers 6

2

You can also use the PHP function is_a() in addition to the PHP function get_class().

This is a bit different as it also matches classes which have the class as one of its parents, e.g. an element class that extends craft\elements\User.

Example:

if (is_a($element, 'craft\elements\User')) {
    // Do stuff
}

or

if (is_a($element, craft\elements\User::class)) {
    // Do stuff
}
7

Having arrived here from a Google search while trying to do this in Twig rather than PHP, I thought it might help someone in future to leave an answer, even though it doesn't address your question directly:

{{ item is instance of('craft\\elements\\Entry') ? 'This element is an entry!' }}
{{ item is instance of('craft\\elements\\Asset') ? 'This is an asset!' }}
{{ item is instance of('craft\\elements\\Category') ? 'This is a category!' }}
{{ item is instance of('craft\\elements\\User') ? 'This is a user!' }}
{{ item is instance of('craft\\commerce\\elements\\Product') ? '' }}

I find this especially useful in, for example, internal keyword search results listings templates, where the elements that were found might be of different types and you want to take different actions depending on the types.

Edit 2024 to add: You can also fetch the element type a little more succinctly like this, however (and it's a big HOWEVER!), beware that this requires a database query - so if you're inside a loop, which is probably quite likely given the use case for this, it's going to give you a horrible N+1 problem which will slow down your template:

{# you probably shouldn't do this due to the N+1 problem it'll cause : #}

{{ craft.app.elements.getElementTypeById(item.id) }}
2

There’s no dedicated method on elements, but you can use get_class().

switch (get_class($element)) {
    case Entry::class:
        // it’s an entry
        break;

    case Category::class:
        // it’s a category
        break;
}
2
  • Just a simple question, would you mind to explain why you use 2 different functions here? I know the behavior of ::class and get_class I would just like to know why you use get_class(element) == Entry::class instead of element::class == Entry::class Commented Mar 9, 2018 at 20:36
  • They are both very different, ::class returns the fully qualified class name for a class name and get_class() the fully qualified class name for an instance of a class.
    – carlcs
    Commented Mar 12, 2018 at 9:20
1

I just discovered getElementTypeById()

This pretty much does the trick:

  public function getElementType($element) {

    $elementType = Craft::$app->getElements()->getElementTypeById($element->id);

    if (strpos($elementType, 'Category') !== false) {
      return 'category';
    } else if (strpos($elementType, 'Entry') !== false) {
      return 'entry';
    }

  }
1

Example: do nothing if element is not Entry

if (!$event->element instanceof \craft\elements\Entry) { return; }
1

This is a trick I always use when I want the "base name" of a class:

// if $element is an instance of \craft\elements\Entry
$baseName = array_reverse(explode('\\', get_class($element)))[0]; // 'Entry'
$type = strtolower($baseName); // 'entry'

explode('\\', get_class($element)) gives you an array like ["Entry", "elements", "craft"], so at position 0 you will find the class "base name" which we can use as a type string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.