In some special cases, users may want to search on other data other than just the title field.
Currently, in EntityMatcher, there is logic that gets the label key for the entity type.

$label_key = $entity_type->getKey('label');
Which, for node entities, is the title.

Which is then used in the conditions in the ->buildEntityQuery() method.

if ($label_key) {
      // For configuration entities, the condition needs to be CONTAINS as
      // the matcher does not support LIKE.
      if ($entity_type instanceof ConfigEntityTypeInterface) {
        $query->condition($label_key, $search_string, 'CONTAINS');
      }
      else {
        $query->condition($label_key, '%' . $search_string . '%', 'LIKE');
      }

      $query->sort($label_key, 'ASC');
    }

It seems like we could add a custom form element that allows the user to specify what field to use as that key in the condition. It would need to be dynamically worked out based on which entity and bundles were configured in the Matcher.

I tried the patch in #6 (against 7.0.9) and although it applied without error, it didn't seem to do anything. The custom matcher approach works well, though, and I think offers greater customization and flexibility (but does of course require some coding).

Thanks all!

Issue fork linkit-2962821

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

joshua.boltz created an issue. See original summary.

rdeboer’s picture

I would also very much like this functionality, being able to get the autocomplete matcher widget to find content based on a keyword or phrase mentioned in say, the body of that content.

glardup’s picture

+1

mrshowerman’s picture

+1
We often add a "Long title" field to our content types, to be displayed in the frontend, and use the system title only in the backend. So it would be nice if editors could search for the long title as well.

jonmarshall’s picture

+1

jacobbell84’s picture

Version: 8.x-5.x-dev » 6.0.x-dev
Status: Active » Needs review
StatusFileSize
new2 KB

I had need of this functionality so I put together a patch. Because there's a lot of possible use cases, more then can be handled by a form field, I introduced hooks so that the developer can add support for whatever field they're looking for. One allows for the field to be searched on, the other allows you override the label that gets returned.

igorgoncalves’s picture

Ok, i faced a similar situation like many others here, so i will share the step-by-step i made to achieve the solution.

1 - We have a product content type with a product_id field. So the editor wants to search not only by the product title, but by the product id as well.

2 - On yours custom module you will need to create a new Linkit Matcher.

3 - so, on my 'custom_module' i created:

docroot/modules/custom/custom_module/src/Plugin/Linkit/Matcher/NodeProductsMatcher.php

4 - and the code below:

<?php
namespace Drupal\custom_module\Plugin\Linkit\Matcher;
use Drupal\linkit\Plugin\Linkit\Matcher\NodeMatcher;

// Those anotations below it is VERY important to follow the patterns from NodeMatcher parent.

/**
 * Provide specific linkit matcher for products CT.
 *
 * @Matcher(
 *   id = "custom_module:node:products",
 *   label = @Translation("Custom Matcher Products"),
 *   target_entity = "node",
 *   provider = "node"
 * )
 */
class NodeProductsMatcher extends NodeMatcher {
  /**
   * {@inheritdoc}
   */
  protected function buildEntityQuery($search_string) {
    $search_string = $this->database->escapeLike($search_string);
    $entity_type = $this->entityTypeManager->getDefinition($this->targetType);
    $nodeQuery = $this->entityTypeManager->getStorage('node')->getQuery();
    $nodeQuery->condition('field_product_id', '%' . $search_string . '%', 'LIKE');
    // Bundle check.
    if (!empty($this->configuration['bundles']) && $bundle_key = $entity_type->getKey('bundle')) {
      $nodeQuery->condition($bundle_key, $this->configuration['bundles'], 'IN');
    }
    if ($this->configuration['limit']) {
      $nodeQuery->range(0, $this->configuration['limit']);
    }
    $this->addQueryTags($nodeQuery);
    return $nodeQuery;
  }
}

5 - Save, clear your cache, and go back to UI and add your new Custom Matcher at: admin/config/content/linkit/manage/[Your-profile-default]/matchers

6 - Select the content which have your product_id field, and save.

7 - long story short here, the new NodeProductsMatcher will be called and the buildEntityQuery function there will look for field_product_id, instead of the $node->label() as the default one. The bundle check and the config['limit'] will heritage what you've selected on step 6.

8 - thats it, you now have your suggestions updated.

mark_fullmer’s picture

Version: 6.0.x-dev » 7.x-dev
jannakha’s picture

Status: Needs review » Needs work

@jacobbell84 can you please create a merge request our of patch for a faster review and testing?

mrinalini9 made their first commit to this issue’s fork.

mrinalini9’s picture

Status: Needs work » Needs review
kasey_mk’s picture

Issue summary: View changes

Thank you @igorgoncalves! With your note I was able to make custom matchers for both nodes and media, matching against a couple fields on nodes and against filenames on media.

My custom "NodeMetaMatcher" extends NodeMatcher and adds an orConditionGroup as follows to check not only the node title but also the ID, an extra title field we have, and a teaser field:

$nodeQuery = $this->entityTypeManager->getStorage('node')->getQuery();
// Create the orConditionGroup
$orGroup = $nodeQuery->orConditionGroup()
  ->condition('nid', '%' . $search_string . '%', 'LIKE')
  ->condition('title', '%' . $search_string . '%', 'LIKE')
  ->condition('field_hook_title', '%' . $search_string . '%', 'LIKE')
  ->condition('field_long_teaser', '%' . $search_string . '%', 'LIKE');
// Add the group to the query.
$nodeQuery->condition($orGroup);

My custom "MediaMetaMatcher" extends EntityMatcher (and all other 'node' references from your example changed to 'media') and adds an orConditionGroup as follows to check not only the media name but also the ID and the filenames from three possible file entity reference fields:

$mediaQuery = $this->entityTypeManager->getStorage('media')->getQuery();
// Create the orConditionGroup
$orGroup = $mediaQuery->orConditionGroup()
  ->condition('mid', '%' . $search_string . '%', 'LIKE')
  ->condition('name', '%' . $search_string . '%', 'LIKE')
  ->condition('field_media_file.entity:file.filename', '%' . $search_string . '%', 'LIKE')
  ->condition('field_media_image.entity:file.filename', '%' . $search_string . '%', 'LIKE')
  ->condition('field_media_audio_file.entity:file.filename', '%' . $search_string . '%', 'LIKE');
// Add the group to the query.
$mediaQuery->condition($orGroup);
kasey_mk’s picture

Just a note that new custom matchers require new schema, too.

For mine as noted in #13, I added the following lines to my web/modules/custom/MYMODULE/config/schema/MYMODULE.schema.yml file for each of the matchers I created:

# Plugin \Drupal\MYMODULE\Plugin\Linkit\Matcher\MediaMetaMatcher.php
linkit.matcher.MYMODULE:media:meta:
  type: linkit.matcher.entity
  mapping:
    include_unpublished:
      type: boolean
# Plugin \Drupal\MYMODULE\Plugin\Linkit\Matcher\NodeMetaMatcher.php
linkit.matcher.MYMODULE:node:meta:
  type: linkit.matcher.entity
  mapping:
    include_unpublished:
      type: boolean