• Content count

  • Joined

  • Last visited

Community Reputation

7 Neutral

About ZGD

  • Rank
    Jr. Member

Recent Profile Visitors

1,024 profile views
  1. Not sure if this has been discussed before, but is it possible to use a different method for storing image variations with PW? For example, would it be possible that instead of storing variations like this: /image.jpg /image.2000x0.jpg /image.0x900.jpg Variations were instead stored like this: /image.jpg /2000x0/image.jpg /0x900/image.jpg Normally the default method is fine, but we are working on a project where the image filenames may need to remain unchanged, but variations still produced. If anyone has any information about this it would be much appreciated! EDIT: Having looked at the size method in the Pageimage class, it looks like this isn't something that could be changed easily.
  2. Figured out a slight workaround today using various hooks, it's probably not ideal but seems to work OK. It adds two new fields to every template, the first gives the option to hide view links from pages using that template, the second adds the ability to edit the URL. The following is in my ready.php file: <?php // Helper function to rewrite URLs with dynamic properties // For example {name} will be replaced with the page name property function rewriteURL($page, $url) { $appUrl = wire('pages')->get(1)->link; // Base URL set in home template $regex = '/(?:{([^}]+?)})|(.+?(?={[^}]+?}|$))/'; $out = ''; preg_match_all($regex, $url, $matches, PREG_SET_ORDER, 0); foreach($matches as $match) { if ($match[1]) $out .= $page[$match[1]]; else if ($match[2]) $out .= $match[2]; } return $appUrl.$out; // e.g. http://www.example.com/some-path } // Rewrite page list view URLs $wire->addHook('ProcessPageListActions::getActions', function($event) { $page = $event->arguments(0); $template = $page->template; if ($template->hideViewLink) { $actions = $event->return; unset($actions['view']); $event->return = $actions; } elseif ($template->rewriteViewURL) { $actions = $event->return; if (array_key_exists('view', $actions)) { $actions['view'] = array( 'cn' => $actions['view']['cn'], 'name' => $actions['view']['name'], 'url' => rewriteURL($page, $template->rewriteViewURL), ); $event->return = $actions; } } }); // Rewrite page edit view URLs $wire->addHookBefore('ProcessPageEdit::buildFormView', function($event) { $page = $event->object->getPage(); $template = $page->template; if ($template->rewriteViewURL) { $updatedURL = rewriteURL($page, $template->rewriteViewURL); $event->arguments = [ $updatedURL ]; } }); // Edits the edit page 'View' tab if required // Removes dropdown items $wire->addHookAfter('ProcessPageEdit::getTabs', function($event) { $template = $event->object->getPage()->template; $tabs = $event->return; $editTab = array_key_exists('ProcessPageEditView', $tabs); if ($editTab) { if ($template->hideViewLink) { $tabs['ProcessPageEditView'] = false; } else { $tabs['ProcessPageEditView'] = preg_replace('/<span.*(?=<\/a>)/', '', $tabs['ProcessPageEditView']); } $event->return = $tabs; } }); // Adds extra fields to templates $wire->addHookAfter("ProcessTemplate::buildEditForm", function(HookEvent $event) { $template = $event->arguments[0]; $form = $event->return; $f = $this->modules->get('InputfieldText'); $f->attr('id+name', 'rewriteViewURL'); $f->value = $template->rewriteViewURL; $f->label = $this->_('Rewrite View URL'); $f->description = $this->_('You can access page properties by wrapping them in curly braces.'); $f->notes = $this->_('e.g. {name} will be replaced with the page name'); $form->insertAfter($f, $form->templateLabel); $f = $this->modules->get('InputfieldRadios'); $f->attr('id+name', 'hideViewLink'); $f->addOption(1, 'Yes'); $f->addOption(NULL, 'No'); $f->value = $template->hideViewLink; $f->label = $this->_('Hide View Link'); $f->description = $this->_('If this template should hide view links.'); $form->insertAfter($f, $form->templateLabel); $event->return = $form; }); // Save the extra template fields $wire->addHookBefore("ProcessTemplate::executeSave", function() { $template = $this->templates->get($this->input->post->id); $template->set('hideViewLink', $this->input->post->hideViewLink); $template->set('rewriteViewURL', $this->input->post->rewriteViewURL); }); Also need some custom CSS rules to hide the view link in the dropdown Save button. .pw-button-dropdown .ui-menu-item { display: block } .pw-button-dropdown .ui-menu-item a[data-pw-dropdown-value="view"] { display: none; } Would still be interested in a cleaner solution though!
  3. Bumping this to see if anyone else found a viable solution. We need to be able to redirect users to an app served by a different server as the PW instance just outputs JSON data. Seems like there is no hook available to simply alter the view URL. Would be super useful.
  4. Basically yes, I'm trying to access an unpublished page via an asynchronous request from another server, so it's effectively the same as trying to access it from a browser. My JS app running on the node.js server makes an AJAX request to the ProcessWire specific URL (an unpublished page), but as that session is not authenticated, PW responds with 404.
  5. This is similar to what I'm looking for but I don't think it would work in this case. I would essentially do... $page = $pages->get($page); ... in my template. But if I understand correctly ProcessWire will redirect to the 404 page so I can't actually run this code in my template. I guess I would need to somehow hook into the page render method and prevent this 404 redirect?
  6. TL;DR: Is it possible to render unpublished pages even if the request comes from an unauthenticated user? I'm currently building a website that consists of a two parts: A front-end 'app' built using Vue.js served by a node.js/express server (necessary for server-side rendering). A ProcessWire back-end that serves up a JSON API, this is running on an Apache server. I've added hooks so the "View" page links/tabs in ProcessWire direct to the front-end app's URLs, rather than just showing a page of the raw JSON data exposed by ProcessWire. So for example if my PW page lives at https://api.example.com/pages/foo, clicking View directs to a URL pointing to the front-end app like https://example.com/foo. The problem I now have is that I need to be able to view unpublished pages. As sessions are not shared between ProcessWire and the front-end as they run on different servers, this means if I redirect to the app from PW as above, the app then makes a request to PW and obviously returns a 404. PW rightly sees the request from the app as coming from an unauthenticated user. My proposed solution is that I edit the page preview hook to include a query in the URL like so https://example.com/foo?session=a1b2c3d4e5. The front-end server then passes this query string to any requests it makes to the PW API (e.g. https://api.example.com/pages/foo?session=a1b2c3d4e5), which in turn checks it against a list of valid session variables (even better if I could somehow check this against a session_id of logged in users). If the query was valid, then PW should render the page even if it is unpublished. Is this possible?
  7. Managed to resolve this, code below for any that's interested. My translations class: <?php namespace Translations; class Translation { private function __construct() {} protected static function translations() { return []; } private static function initialize() { $languages = \ProcessWire\wire('languages'); $user = \ProcessWire\wire('user'); $translated = []; foreach($languages as $lang) { $user->language = $lang; foreach(static::translations() as $k => $t) { $translated[$k][$lang->language_code] = $t; } } return $translated; } public static function translate() { return static::initialize(); } } include_once __DIR__ . '/greetings.php'; include_once __DIR__ . '/questions.php'; Now I can create as many different translation files as I like, for example greetings.php <?php namespace Translations; use function ProcessWire\__ as __; class Greetings extends Translation { protected static function translations() { return [ 'hello' => __('Hello'), // A casual greeting message 'goodbye' => __('GoodBye'), // A casual departing message ]; } } and questions.php <?php namespace Translations; use function ProcessWire\__ as __; class Questions extends Translation { protected static function translations() { return [ 'howareyou' => __('How are You?'), 'howmuch' => __('How Much?'), ]; } } So in my template I can now write: <?php use Translations\Greetings; use Translations\Questions; $greetings = Greetings::translate(); $questions = Questions::translate(); // ... output here
  8. I'm using PW to build an API which returns data in multiple languages at once. For example I might have the words "Hello" and "Goodbye" that need to be translated into several languages. The API (which returns data as JSON) needs to return something like the following... { "hello": { "de": "Hallo", "en": "Hello", "fr": "Bonjour", "it": "Ciao", "tc": "你好" }, "goodbye": { "de": "Auf Wiedersehen", "en": "Goodbye", "fr": "Au Revoir", "it": "Addio", "tc": "再見" } } Ideally I'd like to be able to use PW's template string translating feature, as there will be potentially hundreds of different translations and creating many fields seems the wrong way to go. Each translation will also need to have a note or description alongside it. I was originally thinking something like the example below may be possible, but it seems unlikely. <?php function _t($translation) { // logic to return all translations here... return $translation; } $translations = [ 'hello' => _t(__('Hello')), // A casual greeting message 'goodbye' => _t(__('Goodbye')) // A casual departing message ]; echo json_encode($translations); Can anyone suggest a good method for returning all translations of a translatable string? Is it even possible to access multiple translations of static strings within a template? Alternatively, if anyone has solved a similar problem before, I'm open to suggestions. Thanks!
  9. I'm also seeing this, did you find a workaround? EDIT: Prepended the ProcessWire namespace to the wirePopulateStringTags method which seems to have fixed the problem for now.
  10. @kongondo Do you know if this is something that is being built already? I'd like to contribute if possible.
  11. Thanks @LostKobrakai. That all makes sense. I'd estimate less than 5% of images will have alternatives, so the manual uploading for those would be manageable. Being able to drag and drop multiple images at once is really the priority, but I had a better look through all the core modules earlier and decided the development time to create something custom probably wasn't worth it for this project. I looks like we will have to go with a repeater or pagetable approach as you've suggested.
  12. Nope not quite, sorry I probably wasn't very clear there. Drag-and-drop does indeed work inside repeaters, my problem is that if I need to separate each image and its associated crop in the image grid into a separate repeater with an image field then I can't drag-and-drop say 20 images at once. I have to manually drag each image to the associated field in the repeater array. An ideal situation would be the ability to store a secondary image with each image. For example each image has an input for alt text, I would somehow like there to be another input for another image. Essentially nested images. CroppableImage3 is great but it also won't work for this as the images are prepared outside of PW as they have various other applications. The crops also aren't systematic and we also need to support the option for the crop being a completely different image entirely.
  13. I'm currently developing a site where some image fields need to be able to have two images associated with them, a thumbnail and a full sized image (which is often a different crop) which will be shown in a lightbox view. This is fine for most templates, I'm just using normal image fields that return an array and support up to two images. If a second image is present in the field then it will be used as the alternative image for the lightbox. If only one image is present, it will be used for both thumbnail and full sized (the template resizes for the thumbnail using the API). However I have templates with flexible layouts using a repeater matrix, and one of the matrix types is an 'image grid'. This is an image field that supports an unlimited number of images, so obviously this method is not suitable here. I've tried creating a repeater in this matrix type which contains an image field (each supporting two images, as above), but this means that I can no longer drag and drop multiple images at once. Each image in the grid has to be uploaded individually which is a big problem as there are many instances of these grids with a large number of images. I've tried the ImageExtra module but it seems you can't add an image field as a secondary field. Any suggestions as to how I might solve this problem?
  14. I've looked through the forum and various issues on Github and can't seem to find a definitive answer for this. It seems some Lazycron hooks have stopped working reliably on one of my PW installations. The function which adds the hooks is triggered successfully every minute and logs a message (I've tested the cronjob and it is working correctly), however it seems the hook itself is being very temperamental. This line in the module's init method should add a hook for every minute: $this->addHook("LazyCron::everyMinute", $this, 'myFunction'); The first line of myFunction logs a string whenever it is executed, before doing anything else. I've been watching the module log all day and this function seems to execute each minute up to around 5 times, and then stops executing. I've been monitoring the site's cache folder, and sometimes deleting the LazyCron.cache file resolves the problem temporarily, other times it does not. Sometimes if I leave everything alone for a few hours, myFunction starts executing again. Unlike other people who have reported similar issues, I don't have have a LazyCronLock.cache file that is causing problems. I can't work this one out, has anyone encountered something similar?
  15. Ah I understand now, I hadn't realized single quotes were used for literal strings. All makes sense and the above code seems to do the trick, thanks once again!