Jump to content

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


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 post
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 post
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 post
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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By spercy16
      These issues should be fairly easy for any intermediate to advanced ProcessWire developer to answer. I'm new to PHP and relatively new to ProcessWire and just need a bit of help. What I'm trying to do is bring in a couple of cards from my Projects page to display on my home page. I finally got the code right to bring in the cards but right now they're using my original images instead of my resized "variations". So firstly, I would like to know how to reference the variations of my images instead of using the original. Secondly, I need to grab only four of the cards from the Project page and not import in all ten. It should be just two small changes to my code to do these things (I would imagine). Here is the code I currently have for that section:
      <?php // https://processwire.com/api/arrays/ // check if the array of images has items if (count($pages->get("/projects/")->images)) : // get array of images from the field $images = $pages->get("/projects/")->images; $count = 0; // iterate over each one foreach ($images as $image) : $count++; $sectionText = $pages->get("/projects/")->get("paragraph_$count"); $img = $image; $buttonCode = $pages->get("/projects/")->get("url_$count"); ?> <span id="card<?php echo $count?>" class="card"> <img class="cardThumb" src="<?php echo $img->url; ?>" alt="<?php echo $image->description; ?> Thumbnail" /> <div class="cardBody"> <div class="cardText"> <h2><?php echo $img->description; ?></h2> <?php echo $sectionText; ?> </div> <div class="primaryBtn"> <a href="https://www.paypal.com/donate?hosted_button_id= <?php echo $buttonCode; ?> &source=url"> <button> <i class="fas fa-donate"></i> Donate </button> </a> </div> </div> </span> <?php endforeach; endif; ?> Thanks in advance for any help!
    • By skeltern
      WebP image support is great and works fine. But once created I've issues to get rid of all API generated WebP variations.
      The backend image field variations "Delete" works and I can remove all variations JPEG plus WebP. Image list is clean but all WebP API variations are still stored in file system (for instance files/12345/84.900x675.webp etc). I can only use ImageSizer with temp 'force' option to request fresh WebP variations or have to delete WebP files from folders. No other way so far. Tested with 2 sites and latest master PW 3.0.165.
      Is there somewhere a "magic button" or config/setup thing to solve my sticky WebP issue?
    • By psy
      I've searched, and maybe missed, the solution. I have a 'normal' images field and uploading images with a file size greater than 10Kb is fine. Any image size smaller results in the never-ending spinner and no upload.
      No min/max width/height set on image uploads in admin, ie just the defaults.
      Any ideas on how to fix?
      Using:
      PW: 3.0.175
      PHP: 7.3
      Marking it as "Resolved" rather than "Solved" as it auto-magically fixed itself. No idea whether PW, PHP, or just an internet hiccough... All good now 🤞
    • By rjgamer
      Hi,
      is there a hook after the current (active) page got created? Or which method got called in the Page class after the Constructor of the current page got initialized?
      Thanks.
       
    • By Kiwi Chris
      I need to restrict editing access based on both the user role, and the value of a sub-field in a page reference field.
      eg $page->competition->closingDate 
      There's some discussion about restricting editing access based on role, and that works, but when I try to access the page via the method @Robin S suggests, the page returned is an admin page rather than the page being edited, so I don't have access to the edited page's fields.
       
×
×
  • Create New...