Jump to content

Change 'choose file' image source options to include external media gallery?


modifiedcontent
 Share

Recommended Posts

Is there a way to change the input options for the images field?

I am trying to figure out if it would make sense to use an external script like Zenphoto as a central media library/manager. How could I connect that with Processwire?

'Choose File' in the images field would have to be able to open that 3rd party media library or a directory on the server or some cloud service instead of (only) the client file manager.

Could justb3a's field type module Image Extra be part of the solution? I will try that and report back. Other field types/modules?

I know there is a pro module Media Manager that does look very slick, but would prefer to make this work with a mature, tested 3rd party script if a central media gallery is never going to be a core Processwire feature.

Link to comment
Share on other sites

Hello.

7 hours ago, modifiedcontent said:

'Choose File' in the images field would have to be able to open that 3rd party media library or a directory on the server or some cloud service instead of (only) the client file manager.

There are few possible problems with centralised concept. As example, what to store in that images field? To be more clear, if some image is part of PW page only as reference link, than how can we resize it (eg. "on the fly" in page rendering process)? What would happened when someone delete image on that external point - how would ProcessWire page know that? Etc...

Because of that, if I go to build that module/field type than probably it will copy image from that external central point to ProcessWire page. With that, we can have external Media manager where we can use all it's power (organise files to folders, search etc.). Also, because we have on PW side copy of that file we can use all PW API power to manipulate with it - on PW side.

Here was few discussions why PW by default doesn't have "Media manager" like many others CMS's (I was one with that question too) but very soon undrestand that maybe because of that some other popular CMS's still doesn't have simple solution to store and generate various dimensions intro images. If some CMS's had that option, need to look closely to see how and where they store eg. that intro images... Storing concept is very important (eg. in case when need to do some export or imports).

That what you ask is completly ok, but also it's important to think about possible consequences.
What I like in centralised Media manager idea is 1 central point for file organisations, all other with that idea bring us problems and complicate things.
Regards.

Link to comment
Share on other sites

OLSA, thanks for your feedback. I personally like how Processwire handles images, but I have a client who wants a central media library.

That is why I want to create an external media library - Zenphoto in my case - and have Processwire "upload" the images from there instead of from a client OS file manager.

How can I modify 'choose file' in the image field to use other source options? Is it possible to have that open a web-based file manager of another script on the server or on a cloud service, AWS, whatever?

 

Link to comment
Share on other sites

Thanks dragan, but those threads really focus on uploading to AWS. I am looking for a way to download from an external library, instead of the client machine. I don't mind if the images are then stored/uploaded in the regular PW way.

How can I modify 'choose file' in the image field to open a file manager on a URL, instead of a client machine OS file manager?

Link to comment
Share on other sites

It's a little bit more involved that just "opening a file manager on a URL", since you have to get the necessary information back to PW, tell it to download the image in question and add it to a page field. Here's a small module that can do that, but it's little more than a starting point (no checking of that image is already there, for example, no live updating the image fields in the page editor) and that requires a rest api plugin on Zenphoto's side.

Spoiler

<?php

/**
 * Download photos from your Zenphoto galleries into your PW image fields
 * from within PW's image picker in CKEditor
 *
 * Needs zen_json_rest_api installed in Zenphoto
 * from https://github.com/deanmoses/zenphoto-json-rest-api
 * and URL Rewrite active in Zenphoto.
 *
 * Note: if you run Zenphoto on Windows, you will have to add a fix
 * to zen_json_rest_api. Edit json_rest_api and modify the dateToTimestamp
 * function according to https://github.com/deanmoses/zenphoto-json-rest-api/issues/14
 *
 * Beware: I have no clue if Permissions are honored on Zenphoto's side,
 * and no idea if introducing access control there blows things up.
 *
 * License:
 * This module is released under the WTFPL.
 * Feel free to do with this code whatever you want.
 *
 */
 

class ZenPhoto extends WireData implements Module, ConfigurableModule {

	public static function getModuleInfo() {
		return array(
			'title' => 'Zen Photo',
			'summary' => 'Allow browsing a Zenphoto installation and importing media from there. Zenphoto must have zenphoto_json_rest_api plugin active.',
			'version' => "0.0.4",
			'autoload' => true
		);
	}
	
	public function init() {
		$this->addHook("ProcessPageEditImageSelect::executeZenPicker", $this, "executeZenPicker");
		$this->addHook("ProcessPageEditImageSelect::executeZenDownload", $this, "executeZenDownload");
		$this->addHookAfter("ProcessPageEditImageSelect::execute", $this, "execute_addButton");
	}
	
	public function execute_addButton(HookEvent $event) {
		$this->initPages($event->object);

		$html = $event->return;
		
		$btn = $this->modules->get('InputfieldButton');
		$btn->href = $this->makeExecLink("picker");
		$btn->value = $this->_('Import ZenPhoto Image');
		$btn->addClass('upload pw-modal-button'); 
		$btn->icon = 'link';

		$out = $btn->render();
		
		$html = preg_replace('~</div>$~', "<p>" . $out . "</p>" . '$1', $html);
		$event->return = $html;
	}
	
	public function executeZenPicker(HookEvent $event) {
		$this->initPages($event->object);

		if(! $this->zenphotoURL) {
			$event->return = "<p><strong>" . $this->_("No Zenphoto URL configured. Go to Modules -> Configure -> Zen Photo and set a valid URL to your Zenphoto installation.");
			return;
		}

		$albumPath = $this->input->get->album;
		$url = $this->zenphotoURL;
		
		if($albumPath) {
			$url .= $albumPath;
		}
		
		$galery = "<div>";
		
		$zenGalery = $this->getJson($url);
		
		if($zenGalery !== FALSE) {
			$galery .= "<h3>" . sprintf($this->_("Albums in %s"), $albumPath ?: "/") . "</h3>" .
					"<div>";
			if($albumPath) {
				$parentAlbum = rtrim(preg_replace('~[^/]+$~', '', $albumPath), "/");
				$galery .= "<div style='width: 160px; height: 160px; display: inline-block; padding: 0.5em; vertical-align: top;'>" .
						"<a href='" . $this->makeExecLink("picker") . "&album={$parentAlbum}'>" .
						"..<br>" .
						$this->_("Return to parent album ") . "</a>" .
						"</div>";
				
			}
			foreach($zenGalery->album->albums as $album) {
				$galery .= "<div style='width: 160px; height: 160px; display: inline-block; padding: 0.5em; vertical-align: top;'>" .
						"<img style='max-width: 120px; max-height: 120px;' src='" . $album->url_thumb . "' alt='" . $album->title . "' title='" . $album->title . "'><br>" .
						"<a href='" . $this->makeExecLink("picker") . "&album={$album->path}'>" .
						$this->_("Browse album: ") . $album->title . "</a>" .
						"</div>";
			}
			if(! $zenGalery->album->albums) {
				$galery .= "<div style='width: 160px; height: 160px; display: inline-block; padding: 0.5em; vertical-align: top;'>" .
						$this->_("No child albums defined") .
						"</div>";
			}
			$galery .= "</div>" .
					"<h3>" . sprintf($this->_("Images in %s"), $albumPath ?: "/") . "</h3>" .
					"<div>";
			foreach($zenGalery->album->images as $image) {
				$galery .= "<div style='width: 160px; height: 180px; display: inline-block; padding: 0.5em; vertical-align: top;'>" .
						"<img style='max-width: 120px; max-height: 120px;' data-url='" . $image->path . "' src='" . $image->url_thumb . "' alt='" . $image->title . "' title='" . $image->title . "'><br>" .
						"<a href='" . $this->makeExecLink("download") . "&image={$image->url_full}&imagename=" . basename($image->path) . "'>" .
						$image->title . " (" . $image->width . "x" . $image->height . ") [" . strftime($this->_("%Y-%m-%d %H:%M"), $image->date) . "]</a>" .
						"</div>";
			}
		}
		$galery .= "</div>" .
				"</div>";
		
		$event->return = $galery;
	}

	private function makeExecLink($action) {
		return "./zen-" . $action . "?modal=1&id={$this->page->id}&edit_page_id={$this->editorPage->id}";
	}

	public function executeZenDownload(HookEvent $event) {
		$this->initPages($event->object);
		
		if(! $this->zenphotoURL) {
			$event->return = "<p><strong>" . $this->_("No Zenphoto URL configured. Go to Modules -> Configure -> Zen Photo and input the URL of your Zenphoto installation.");
			return;
		}

		if(! $this->input->get->assignfile) {
			// Download selected image
			$url = $this->input->get->image;
			$name = $this->input->get->imagename;
			
			if(! strlen($url) || ! strlen($name)) {
				$event->return = "<p><strong>" . $this->_("Missing parameters for image.");
				return;
			}
			
			$tempName = $this->getImage($url, $name);
			
			$toPage = $this->page ?: $this->editPage;
			
			$this->log->message("toPage = " . $toPage->id);
			
			$imageFields = array();
			foreach($toPage->template->fields as $fld) {
				if($fld->type instanceof FieldtypeImage) {
					$imageFields[] = $fld;
				}
			}
			
			$form = $this->modules->get("InputfieldForm");
			$form->label = sprintf($this->_("Add image to page %s"), $toPage->title);
			$form->action = "./zen-download";
			$form->method = "get";
			
			$f = $this->modules->get("InputfieldHidden");
			$f->attr('name', "id");
			$f->attr('value', $this->page->id);
			$form->add($f);
			
			$f = $this->modules->get("InputfieldHidden");
			$f->attr('name', "edit_page_id");
			$f->attr('value', $this->editorPage->id);
			$form->add($f);
			
			$f = $this->modules->get("InputfieldHidden");
			$f->attr('name', "topage");
			$f->attr('value', $toPage->id);
			$form->add($f);
			
			$f = $this->modules->get("InputfieldHidden");
			$f->attr('name', "tempimage");
			$f->attr('value', $tempName);
			$form->add($f);
			
			if(count($imageFields) > 1) {
				// Show a select dropdown if there is more than one possible image field
				$f = $this->modules->get("InputfieldSelect");
				$f->attr('name', 'targetField');
				$f->label = $this->_("Select target image field on page");
				foreach($imageFields as $fld) {
					$f->addOption($fld->name, $fld->label);
				}
				$f->required = true;
			} else {
				$f = $this->modules->get("InputfieldHidden");
				$f->attr('name', 'targetField');
				$f->attr('value', $imageFields[0]->name);
			}
			$form->add($f);
			
			$urlCmp = parse_url($this->zenphotoURL);
			
			$fullUrl = $urlCmp["scheme"] . "://" . $urlCmp["host"] . ":" . $urlCmp["port"] . $url;

			$f = $this->modules->get("InputfieldMarkup");
			$f->attr('value', "<img src='$fullUrl' />");
			$form->add($f);
			
			$btn = $this->modules->get("InputfieldSubmit");
			$btn->attr('name', "assignfile");
			$btn->attr('value', $this->_("Import this image"));
			$form->add($btn);
			
			$event->return = $form->render();
		} else {

			$toPage = $this->pages->get((int)$this->input->get->topage);
			$tempimage = $this->input->get->tempimage;
			$targetField = $this->sanitizer->fieldName($this->input->get->targetField);

			$toPage->of($false);
			$img = new Pageimage($toPage->{$targetField}, $tempimage);
			$toPage->{$targetField}->add($img);
			$toPage->save($targetField);
			
			unlink($tempimage);
			
			$this->session->redirect($this->config->urls->admin . "page/image/edit?modal=1&file={$toPage->id},{$img->name}&id={$toPage->id}&edit_page_id={$this->editorPage->id}");
		}
	}

	private function initPages($imageSelect) {
		$id = (int) $this->input->get->id; 
		$editID = (int) $this->input->get->edit_page_id; 
		if(! $editID) {
			$editID = $this->session->get($imageSelect, 'edit_page_id');
		}
		if($editID) {
			$this->editorPage = $this->wire('pages')->get($editID); 
		}
		if($id) {
			$this->page = $this->wire('pages')->get($id);
		}
	}

	public function getModuleConfigInputfields(array $data) {
		$inputfields = $this->wire(new InputfieldWrapper());

		$f =  $this->wire('modules')->get('InputfieldText');
		$f->attr('name', 'zenphotoURL');
		$f->label = $this->_("Zenphoto URL");
		$f->description = $this->_("Base URL of the Zenphoto installation");
		$f->attr('value', isset($data['zenphotoURL']) ? $data['zenphotoURL'] : '' );
		$inputfields->add($f);
		
		return $inputfields;
	}
	
	public function getJson($url) {

		$url = rtrim($url, "/") . "/";

		$ch = curl_init();

		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_URL, $url . "?json");

		$result = curl_exec($ch);

		curl_close($ch);

		if($result === FALSE) return $result;
		
		$decoded = json_decode($result);
		if($decoded === NULL) {
			$this->log->error(sprintf($this->_("Invalid JSON return in ZenPhoto::getJSON from %s"), $url));
			return FALSE;
		}
		
		return $decoded;
	}
	
	public function getImage($url, $name) {
		$http = new WireHTTP();
		
		$tmpname = $this->config->uploadTmpDir . $name;
		
		$urlCmp = parse_url($this->zenphotoURL);
		
		$fullUrl = $urlCmp["scheme"] . "://" . $urlCmp["host"] . ":" . $urlCmp["port"] . $url;
		
		$http->download($fullUrl, $tmpname);
		
		return $tmpname;
	}
}

 

 

  • Like 6
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...