Jump to content
ryanscherler

Sort Images via API (outside PW admin)

Recommended Posts

I was wondering if it's possible to sort user images via the API. I have added an 'images' custom field to the user template and am creating an outside login for artists (users with PW role 'artist') to edit their profile. This involves allowing them to upload images into their 'gallery' and sort them (via drag-n-drop) once uploaded. I was hoping there was some sort of 'sort' field that I could update via the API, but no luck there. I looked into how the admin allows this functionality and it's a bit over my head digging in the images field module. Any help would be greatly appreciated!

- Ryan

Share this post


Link to post
Share on other sites

I don't think you have this option via the API... The only way i can think of doing it without messing around with the dB, would be creating an extra field that would have a sequence like "0,1,2,3,4,5,6,7" with the same number has the amount of pictures, and updated accordingly to change the order of the pictures in the frontend "4,7,2,1,6,3,0,5".

To output the pictures, you would convert the field to an array and iterate through it.

$sequence = explode(",", $page->extra_field);
$images = $page->images;
foreach ($sequence as $i){
$image = $images->eq($i);
echo "<img src='{$image->url}' alt='{$image->description}'>";
}

too complicated?

Share this post


Link to post
Share on other sites

I think the only way is to remove the images and add them in the new order again. So you could construct a form with this in mind.

Share this post


Link to post
Share on other sites

Soma, you can do this without having to upload them again?

Share this post


Link to post
Share on other sites

diogo, sure

$img = $page->images->first();

$page->images->remove($img);
$page->images->add($img);
$page->save();

and the first image is at last position

  • Like 1

Share this post


Link to post
Share on other sites

You actually can use the 'sort' property, but you'll want to perform the sort after you've assigned it to all your items, because PW will write them out in the order that they appear. For instance, here is how we might reverse the order:

$cnt = count($page->images); 

foreach($page->images as $image) {
 $image->sort = $cnt;
 $cnt--; 
}

// now tell it to sort by the field 'sort'
$page->images->sort('sort'); 

// you may not need to do this, but putting it here just in case
$page->trackChange('images'); 

$page->save();

Avoid calling $page->images->remove() just because that will queue an actual file to be removed when the page is saved.

Another way you might accomplish reversing the order:

$myImages = new Pageimages($page); 
foreach($page->images as $image) {
 $myImages->prepend($image); 
}
$page->images = $myImages; 
$page->save();
  • Like 4

Share this post


Link to post
Share on other sites

I also tried something similar as your code, but it didn't work regardless of what I tried. I think I missed the $page->images->sort("sort"); and to do the trackChange on the field instead of the sort or page. Thanks Ryan for clarifying.

I don't get why removing and readding would be a problem. Seems to work well.

Edit: Just wondering, but why does echo $image->sort not output anything?

Share this post


Link to post
Share on other sites

Thanks for all the feedback on this post! - I will try some various options.

On a side note: I am a bit confused as to the 'trackChange' method (why it exists) as I did see it in the inputField module as follows:

if($changed) {

$this->value->sort('sort');

$this->trackChange('value');

}

Share this post


Link to post
Share on other sites

It's there to tell PW that the value has changed.

Share this post


Link to post
Share on other sites
I don't get why removing and readding would be a problem. Seems to work well.

If it works for you it should be okay. But I think that behind the scenes, it's actually physically deleting a file at some point. Do your filenames change at all when you do this? (i.e. like get a number appended to the end of them)

Edit: Just wondering, but why does echo $image->sort not output anything?

The $image->sort was for our use as a temporary variable. Not actually used by the core.

On a side note: I am a bit confused as to the 'trackChange' method (why it exists) as I did see it in the inputField module as follows:

That is just a way to tell the $page that something about the value changed. The $page may not know that the value changed because it's the same object instance (of Pagefiles) that the $page started with. A $page doesn't know all the inner workings of fields it deals with. As far as it can tell, it's still dealing with the same value.

Some types notify the page of the change automatically, and it may be the case here too, but I wasn't positive without testing it. So we were notifying the page just to be safe.

In my second example, it wasn't even a consideration to do a trackChange() because we actually set a new value to the $page (which it can definitely see).

  • Like 1

Share this post


Link to post
Share on other sites

Bumping this as I'm trying to figure out how to replace an image with an uploaded one.

The only difference from the above is that I'm not using an array for image.

Like Soma I figured that for my new uploaded image file to overwrite the existing one I would have to delete it before adding the new one.

I have tried remove, unset, delete but can't seem to figure out how to do this?

If it's impossible I could always use an array of images and call out the most recent I suppose.

Share this post


Link to post
Share on other sites

You might try something like this for replacing an image. You add the new image (which places it at the end) then grab it and insert it before or after the old image. Then you delete the old image.

$oldFile = 'myimage.jpg';
$newFile = '/some/path/or/url/myimage2.jpg';

$oldItem = $page->images->get($oldFile); 
$page->images->add($newFile); 
$newItem = $page->images->last(); // get the item just added
$page->images->insertAfter($newItem, $oldItem); 
$page->images->delete($oldItem);
$page->save();
  • Like 1

Share this post


Link to post
Share on other sites

Btw, I just now added a replace() method to WireArray so that we'll have the above contained in 1 function for PW 2.3

  • Like 2

Share this post


Link to post
Share on other sites

Hello all,

I'm trying to get my head around sorting user images as well.

Although, I don't really need to sort them as much as allow the user to choose which image is first.

The scenario would be something like:

1. Present user with a grid of thumbnails showing their existing images. (got this part).

2. User selects an image to "use as profile image".  

3. Selected image is now set to first in the images array

4. $user->save;

Everything I think of seems far too complicated, I'm hoping there is a fairly straightforward way to do this via the API.

A nudge in the right direction would be much appreciated.

Share this post


Link to post
Share on other sites

Would it be nicer/easier to have profile image as a separate image field?

  • Like 1

Share this post


Link to post
Share on other sites

Hadn't thought about it that way.

So I would have a profile_image field and a user_images field, and move images between the 2?

Actually, I would just be assigning an image from user_images to profile_image, no need to remove it from user_images.

That might be the way to go. :)

Share this post


Link to post
Share on other sites

Yep, just always replace the profile image with selected one.

  • Like 1

Share this post


Link to post
Share on other sites

Apeisa,

Nice call. I do see a need to figure out custom sorting eventually (Soma gave me some pointers today on IRC) but in this case your solution is a lot easier.

Share this post


Link to post
Share on other sites

Btw, I just now added a replace() method to WireArray so that we'll have the above contained in 1 function for PW 2.3

Is there any documentation how to use this function, Ryan?

Share this post


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 VeiJari
      Hi, this is the first we are trying to make a page that has only one type of user that has access to every page. 
      The other users should only have a given access to specific pages, not to the whole template.
      My structure
      -Field -Organisation -Project -Report I want that the "measurer" role only has access to "project x" and it's children, but no view access to every project, organisation or field. I've tried to do this with https://modules.processwire.com/modules/page-edit-per-user/ but it still needs a view access to the whole tree to see the "project x" page. Or is there something I haven't figured out?
      Maybe I have to make it via the API: a select field in the "organisation" template where the admins could add the users and then I use hook to update the privileges?
      Have you done something like this and how did you accomplish it?
      Any help would be appreciated.
       
    • By cosmicsafari
      Hi all,
      Before I go potentially wasting time trying to achieve the impossible.
      Can anyone confirm if its possible to have a Page Reference field on a modules config page?
      I'm wanting to essentially just output a list of select able pages based on the a given selector (likely by template at this stage), wherein the select is the pages that the module should apply to etc. I was thinking a simple checkbox list would suffice is asmSelect isn't available.
      Essentially have it display the same way a Page Reference field would display on a template, where you can easily select a bunch of them.
      public function getInputfields() { $inputfields = parent::getInputfields(); $f = $this->modules->get('InputfieldPage'); $f->attr('name', 'testSelect'); $f->setAttribute('multiple', 'checkboxes'); $f->setAttribute('findPagesSelector', 'template=development'); $f->label = 'Test'; $inputfields->add($f); return $inputfields; } Figured something akin to the above would work but can't seem to get rid of this warning on the modules config screen though.

    • By Chris Bennett
      Hi all, I am going round and round in circles and would greatly appreciate if anyone can point me in the right direction.
      I am sure I am doing something dumb, or missing something I should know, but don't. Story of my life 😉

      Playing round with a module and my basic problem is I want to upload an image and also use InputfieldMarkup and other Inputfields.
      Going back and forth between trying an api generated page defining Fieldgroup, Template, Fields, Page and the InputfieldWrapper method.

      InputfieldWrapper method works great for all the markup stuff, but I just can't wrap my head around what I need to do to save the image to the database.
      Can generate a Field for it (thanks to the api investigations) but not sure what I need to do to link the Inputfield to that. Tried a lot of stuff from various threads, of varying dates without luck.
      Undoubtedly not helped by me not knowing enough.

      Defining Fieldgroup etc through the api seems nice and clean and works great for the images but I can't wrap my head around how/if I can add/append/hook the InputfieldWrapper/InputfieldMarkup stuff I'd like to include on that template as well. Not even sure if it should be where it is on ___install with the Fieldtype stuff or later on . Not getting Tracy errors, just nothing seems to happen.
      If anyone has any ideas or can point me in the right direction, that would be great because at the moment I am stumbling round in the dark.
       
      public function ___install() { parent::___install(); $page = $this->pages->get('name='.self::PAGE_NAME); if (!$page->id) { // Create fieldgroup, template, fields and page // Create new fieldgroup $fmFieldgroup = new Fieldgroup(); $fmFieldgroup->name = MODULE_NAME.'-fieldgroup'; $fmFieldgroup->add($this->fields->get('title')); // needed title field $fmFieldgroup->save(); // Create new template using the fieldgroup $fmTemplate = new Template(); $fmTemplate->name = MODULE_NAME; $fmTemplate->fieldgroup = $fmFieldgroup; $fmTemplate->noSettings = 1; $fmTemplate->noChildren = 1; $fmTemplate->allowNewPages = 0; $fmTemplate->tabContent = MODULE_NAME; $fmTemplate->noChangeTemplate = 1; $fmTemplate->setIcon(ICON); $fmTemplate->save(); // Favicon source $fmField = new Field(); $fmField->type = $this->modules->get("FieldtypeImage"); $fmField->name = 'fmFavicon'; $fmField->label = 'Favicon'; $fmField->focusMode = 'off'; $fmField->gridMode = 'grid'; $fmField->extensions = 'svg png'; $fmField->columnWidth = 50; $fmField->collapsed = Inputfield::collapsedNever; $fmField->setIcon(ICON); $fmField->addTag(MODULE_NAME); $fmField->save(); $fmFieldgroup->add($fmField); // Favicon Silhouette source $fmField = new Field(); $fmField->type = $this->modules->get("FieldtypeImage"); $fmField->name = 'fmFaviconSilhouette'; $fmField->label = 'SVG Silhouette'; $fmField->notes = 'When creating a silhouette/mask svg version for Safari Pinned Tabs and Windows Tiles, we recommend setting your viewbox for 0 0 16 16, as this is what Apple requires. In many cases, the easiest way to do this in something like illustrator is a sacrificial rectangle with no fill, and no stroke at 16 x 16. This forces the desired viewbox and can then be discarded easily using something as simple as notepad. Easy is good, especially when you get the result you want without a lot of hassle.'; $fmField->focusMode = 'off'; $fmField->extensions = 'svg'; $fmField->columnWidth = 50; $fmField->collapsed = Inputfield::collapsedNever; $fmField->setIcon(ICON); $fmField->addTag(MODULE_NAME); $fmField->save(); $fmFieldgroup->add($fmField); // Create: Open Settings Tab $tabOpener = new Field(); $tabOpener->type = new FieldtypeFieldsetTabOpen(); $tabOpener->name = 'fmTab1'; $tabOpener->label = "Favicon Settings"; $tabOpener->collapsed = Inputfield::collapsedNever; $tabOpener->addTag(MODULE_NAME); $tabOpener->save(); // Create: Close Settings Tab $tabCloser = new Field(); $tabCloser->type = new FieldtypeFieldsetClose; $tabCloser->name = 'fmTab1' . FieldtypeFieldsetTabOpen::fieldsetCloseIdentifier; $tabCloser->label = "Close open tab"; $tabCloser->addTag(MODULE_NAME); $tabCloser->save(); // Create: Opens wrapper for Favicon Folder Name $filesOpener = new Field(); $filesOpener->type = new FieldtypeFieldsetOpen(); $filesOpener->name = 'fmOpenFolderName'; $filesOpener->label = 'Wrap Folder Name'; $filesOpener->class = 'inline'; $filesOpener->collapsed = Inputfield::collapsedNever; $filesOpener->addTag(MODULE_NAME); $filesOpener->save(); // Create: Close wrapper for Favicon Folder Name $filesCloser = new Field(); $filesCloser->type = new FieldtypeFieldsetClose(); $filesCloser->name = 'fmOpenFolderName' . FieldtypeFieldsetOpen::fieldsetCloseIdentifier; $filesCloser->label = "Close open fieldset"; $filesCloser->addTag(MODULE_NAME); $filesCloser->save(); // Create Favicon Folder Name $fmField = new Field(); $fmField->type = $this->modules->get("FieldtypeText"); $fmField->name = 'folderName'; $fmField->label = 'Favicon Folder:'; $fmField->description = $this->config->urls->files; $fmField->placeholder = 'Destination Folder for your generated favicons, webmanifest and browserconfig'; $fmField->columnWidth = 100; $fmField->collapsed = Inputfield::collapsedNever; $fmField->setIcon('folder'); $fmField->addTag(MODULE_NAME); $fmField->save(); $fmFieldgroup->add($tabOpener); $fmFieldgroup->add($filesOpener); $fmFieldgroup->add($fmField); $fmFieldgroup->add($filesCloser); $fmFieldgroup->add($tabCloser); $fmFieldgroup->save(); /////////////////////////////////////////////////////////////// // Experimental Markup Tests $wrapperFaviconMagic = new InputfieldWrapper(); $wrapperFaviconMagic->attr('id','faviconMagicWrapper'); $wrapperFaviconMagic->attr('title',$this->_('Favicon Magic')); // field show info what $field = $this->modules->get('InputfieldMarkup'); $field->name = 'use'; $field->label = __('How do I use it?'); $field->collapsed = Inputfield::collapsedNever; $field->icon('info'); $field->attr('value', 'Does this even begin to vaguely work?'); $field->columnWidth = 50; $wrapperFaviconMagic->add($field); $fmTemplate->fields->add($wrapperFaviconMagic); $fmTemplate->fields->save(); ///////////////////////////////////////////////////////////// // Create page $page = $this->wire( new Page() ); $page->template = MODULE_NAME; $page->parent = $this->wire('pages')->get('/'); $page->addStatus(Page::statusHidden); $page->title = 'Favicons'; $page->name = self::PAGE_NAME; $page->process = $this; $page->save(); } }  
    • By marcus
      wireshell 1.0.0 is out    
      See Bea's post
       


      -------- Original post -----------
        Now this one could be a rather long post about only an experimental niche tool, but maybe a helpful one for some, so stay with me   Intention Do you guys know "Artisan" (Laravel) or "Drush" (Drupal)? If not: These are command line companions for said systems, and very useful for running certain (e.g. maintenance, installation) task quickly - without having to use the Admin Interface, first and foremost when dealing with local ProcessWire installations. And since it has a powerful API and an easy way of being bootstrapped into CLIs like this, I think such a tool has a certain potential in the PW universe.    It's totally not the first approach of this kind. But: this one should be easily extendable - and is based on PHP (specifically: the Console component of the Symfony Framework). Every command is tidily wrapped in its own class, dependencies are clearly visible, and so on.   ( Here was the outdated documentation. Please visit wireshell.pw for the current one )
    • By horst
      Hi, on a site I want to disable access to original images and only allow to access thumbnails and watermarked image variations.
      EDIT:
      A good solution for protecting original images can be found a bit down in this thread:
       
      Old content of this initial post:
       
×
×
  • Create New...