1

I am trying to get the entries based on multiple fields. Fields can be of type tags, checkbox, radio box, and number.

In my controller currently what I tried is.

$extrafilter will be like

Array
(
    [0] => Array // other field
        (
            [handle] => amenities
            [value] => laundry
        )

    [1] => Array // tag field
        (
            [handle] => technologies
            [value] => 45
        )

)

Code to narrow down the result.

use Craft;
use craft\elements\Entry;
use craft\elements\db\ElementQuery;

$entryQuery = Entry::find();
$entryQuery->section($sectionName);

if ($extrafilter && !empty($extrafilter[0])) {
  $relatedTo = [];
  $fieldList = [];

  foreach ($extrafilter as $key => $value) {
     $relatedTo[] = $value['value'];
     $fieldList[] = $value['handle'];
  }

  $entryQuery->relatedTo = array(
        'targetElement' => array_merge(['and'], $relatedTo),
        'field' => $fieldList,
  );
}
$entries = $entryQuery->all();

This works for Tags but for other fields it dont give any result.

I checked these Questions

  1. Display entries that meet multiple tag params

1 Answer 1

3

I haven't tested it but it should give you a pretty good idea on how to set this up.

public function actionTest() {
    $entryQuery = Entry::find()->section('mySection');

    // All the element relations. For example tags and categories.
    // These have to be Element objects. For example craft\elements\Tag.
    $myArrayWithTags = [/* ... */];
    $myArrayWithCategories = [/* ... */];
    $allRelations = array_merge($myArrayWithTags, $myArrayWithCategories);

    // Filter by relations
    $this->_applyRelationFilter($entryQuery, $allRelations);

    // Filter by custom fields
    $this->_applyFieldFilter($entryQuery, 'myRadioField', 'value2');
    $this->_applyFieldFilter($entryQuery, 'myNumberField', 3);
    $this->_applyFieldFilter($entryQuery, 'myCheckboxField', ['option1', 'option2']);

    // Build response string
    $content = "Entries:<br>";
    $content .= "<pre>" . json_encode($entryQuery->all()) . "</pre>";

    // Respond
    $response = Craft::$app->getResponse();
    $response->content = $content;
    return $response;
}

private function _applyRelationFilter(ElementQuery $query, array $elements) : array {
    $relatedTo = [];

    // Build the list of relations in the correct format
    foreach($elements as $element) {
        array_push($relatedTo, [
            "targetElement" => $element
        ]);
    }

    // Create an array with and as the first value so 
    // the result only contains elements that have all the set relations
    $relatedTo = array_merge(['and'], $relatedTo);

    // Set query relatedTo
    return $query->relatedTo($relatedTo);
}

private function _applyFieldFilter(ElementQuery $query, string $handle, $value) {
    $query->andWhere([
        ('content.field_' . $handle) => $value
    ]);
}

You need to have the following imports:

use Craft;
use craft\elements\Entry;
use craft\elements\db\ElementQuery;

Info about querying by custom field: https://craftcms.stackexchange.com/a/22995/9754

13
  • Thank you for your time. What goes in $myArrayWithTags, handle of tag fields?
    – inrsaurabh
    Commented Jun 5, 2019 at 9:13
  • @inrsaurabh The array should contain Elements. So in your case it would have to be filled with Tag objects (craft\element\Tag). Updated my answer :) Commented Jun 5, 2019 at 9:21
  • Ok, Currently, i am testing _applyRelationFilter in this i am getting an error related to ElementQuery which is ... instance of craft\elements\db\EntryQuery given ...
    – inrsaurabh
    Commented Jun 5, 2019 at 9:28
  • pastebin.com/i9jByDWd Complete error when using ElementQuery
    – inrsaurabh
    Commented Jun 5, 2019 at 9:48
  • @inrsaurabh You need to add the right imports. See my original answer for more details. Edited answer. Commented Jun 5, 2019 at 9:58

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.