Jump to content

[SOLVED] Find all $page->images that do NOT have the given tag(s)


Andi
 Share

Recommended Posts

Continuing my journey into PW hooks, I'm trying to find a way to retrieve all images from a page that explicitly *do not* have a certain tag (or tags) attached to them.

Found this post from 2015

But I'm wondering if there's a more elegant way to go about this.

Let's say I have a multi-image field called "images_header" and instead of

$page->images_header->findTag('mytag');

I would like to do this:

$page->images_header->excludeTag('mytag');

So I'd be able to do

// find images that don't have the tag "mytag"
$images = $page->images_header->excludeTag('mytag');
// check if there's any images
if (count($images)>0) {
	// do something..
}

Would this be possible by hooking into Pagefiles somehow?

There's this bit in /wire/core/Pagefiles.php Line 626 that I'd basically just need to reverse (or at least in my mind ? )

public function findTag($tag) {
	$items = $this->makeNew();		
	foreach($this as $pagefile) {
		if($pagefile->hasTag($tag)) $items->add($pagefile);
	}
	return $items; 
}

Any ideas on how this could be done in a graceful manner?

Thanks in advance!

Link to comment
Share on other sites

How to add a new method with a hook.

So if you take your that code from Pagefiles->findTag():

/**
 * Return all Pagefile objects that do NOT have the given tag(s).
 * 
 * Given tag may be any of the following:
 * 
 * - `foo` (single tag): Will return all Pagefile objects not having the specified tag.
 * - `foo|bar|baz` (multiple OR tags): Will return Pagefile objects having not having ANY of the tags listed.
 * - `foo,bar,baz` (multiple AND tags): Will return Pagefile objects having NONE of the tags listed.
 * - `['foo','bar','baz']` (multiple AND tags array): Same as above but can be specified as an array.
 *
 * @param string|array $tag
 * @return Pagefiles New Pagefiles array with items that didn't match the given tag(s).
 * @see Pagefiles::getTag(), Pagefile::hasTag(), Pagefile::tags()
 *
 */
wire()->addHook('Pagefiles::excludeTag', function (HookEvent $event) {                
	$pagefiles = $event->object; //the Pagefiles object. For every instance of $this from the original code we will use $pagefiles instead.
	$tag = $event->arguments(0); //the argument passed to the method. so it will be e.g. $images->excludeTag($tag)

	$items = $pagefiles->makeNew();
	foreach($pagefiles as $pagefile) {
		if(!$pagefile->hasTag($tag)) //the only real change is introducing this exclamation mark to negate the condition
			$items->add($pagefile);
	}
    
	$event->return = $items;
});

Now because we just negate the result of $pagefile->hasTag(), we need to be aware of the inverted logic. If you pass multiple tags it should act the way I described in the comment above, which is just Ryan's comment inverted. So if you pass 'foo,bar,baz', you may still get images tagged as 'foo'.

(i haven't tested any of this. i may have done it completely wrong.)

Edit: Apologies, I did indeed do it wrong. Fixed the code above. @Andi

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Dude you're fast! ?

Looking great so far, nice and simple. With this in site/templates/_init.php I can do

// retrieve all images that don't have mytag1
$images = $page->images_header->excludeTag('mytag1');

// retrieve all images that don't have mytag2
$images = $page->images_header->excludeTag('mytag2');

// retrieve all images that have neither mytag1 or mytag2
$images = $page->images_header->excludeTag('mytag1|mytag2');

I'll test this further and report back. Awesome stuff @Jan Romero, much appreciated!!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...