Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 06/20/2021 in all areas

  1. I'm posting this as an update to an earlier post created by @Hari KT: https://processwire.com/talk/topic/4958-composer-support-for-processwire/. Though that approach still (kind of) works (as does the one detailed in https://github.com/wireframe-framework/processwire-composer-installer), thanks to @d'Hinnisdaël there's now a better alternative: the official composer/installers project ? An example repository implementing the things detailed in this post: GitHub repository: https://github.com/teppokoivula/HelloWorld Packagist entry: https://packagist.org/packages/teppokoivula/hello-world As a module author, how do I make my module installable via Composer? 1) Add a composer.json file to your module's directory. Here's an example: { "name": "vendor-name/module-name", "type": "processwire-module", "license": "MIT", "extra": { "installer-name": "ModuleName" }, "require": { "composer/installers": "~1.0" } } The composer.json file explained: "name" consists of two parts: your vendor (author) name, and the name of the package (module). These can (but don't have to) be the same as your GitHub or BitBucket user and repository names. Please note that this value should be all lowercase! That's the syntax expected by both Packagist and Composer. "type" should be "processwire-module". You may have seen "pw-module" used by other packages; that's the value used by third party installers, you don't need to worry about that now. "license" should specify the license your module is published under. See Composer help for expected syntax. It's technically fine to leave this out, but it's always a good idea to let users know how they're allowed to use your code. "installer-name" under "extra" should specify the expected directory name for your module. Usually this is the same as your module's name. If you leave this out, the package part of the "name" value will be used instead (which may be just fine, though I'd recommend always filling in this value). "require" includes Composer dependencies of your module. The key part here is "composer/installers" — without this Composer won't know that your module requires said installer, and it may not be installable at all, so be sure to add this row. 2) Submit your project to Packagist: https://packagist.org/packages/submit. You will need an account for this step. It's free and very easy to register, and you can automatically connect it with your GitHub account. Connecting with GitHub also makes it easier to auto-update package versions from GitHub repository. 3) Recommended but not absolutely necessary: add tags to your module's Git repository. It's recommended that when you push a new version of your module to GitHub or BitBucket, you also add a matching tag: if you push version 0.0.3 (or version "3", following the old school ProcessWire version number format), you should also add tag 0.0.3 (or "v0.0.3" if you want to be verbose) to GitHub/BitBucket. (This step is not strictly speaking necessary, but it does make things easier for users installing your module, and makes much easier to track which version of the module is currently installed via Composer. It requires additional step when publishing a new version of the module, but please consider doing it anyway!) 4) Also recommended but not absolutely necessary: configure Packagist to auto-update based on GitHub/BitBucket. Follow the instructions here: https://packagist.org/about#how-to-update-packages. This step ensures that once you push a new version of your module, Packagist automatically updates stored information without you logging in and hitting the "update" button manually. (This step may not be necessary if you've already allowed Packagist access to your GitHub account.) ... and that's it. Congratulations, your module is now installable via Composer! As a module user, how do install a module via Composer? Go to your site's root directory and type on the command-line "composer install vendor-name/module-name". You can look up the correct details from Packagist, or the module author may have included them in the support forum thread. Obviously this only works for those modules that have implemented Composer installer support as outlined in this tutorial. Note: if you're using a "non-standard" directory structure for ProcessWire — you've moved the root of the project outside the public web root, or something along those lines — check out the custom install paths part of the composer/installers README. The "installer-paths" setting allows you to manually specify a custom install path for the "processwire-module" package type.
    3 points
  2. Hi all ? I made this searchable UIkit 3.x documentation site to share with everyone. The official doc is great but you can't search across the whole doc. Anyway, here is the URL: https://uikitdocs.netlify.app/ What's missing is the live examples. Perhaps some of you can contribute? Github repo link is on the website as well. Cheers
    2 points
  3. Fluency now supports the new DeepL free accounts in the latest release (v0.3.0) which also includes some bugfixes. Now live on the repo. Thank you to @Mr. NiceGuy for notifying me about the new free accounts from DeepL. Very exciting to know that anyone can use Fluency for any project or to play around with at no cost. I hadn't noticed but since Fluency was released in November 2020 DeepL's supported languages has climbed from 12 to over 25 which is really awesome. Looking forward to seeing what languages they add next. Fluency will always offer all languages that DeepL supports as it pulls this information from the API, so no module updates are ever required to take advantage of these. Thanks everyone and bugfixes and feature requests are always appreciated over on the Github repo.
    2 points
  4. Second Episode: "How can I add a watermark to all pageimages of a site?" first episode "Tutorial how to add a site wide optional watermarking method to all pageimages" second episode "Second Episode: "How can I add a watermark to all pageimages of a site?"" In the first episode we created a function that adds a watermark overlay to our original images. This function was hooked via the name "wm" to the pageimage object. We positioned a big centralized overlay to the original images. This suites right if you or your customer will not use cropped portions of the images somewhere down in the site. So, given the setup of the first episode is fine for a sites images concept, one can add a simple security layer to protect the original (unwatermarked) images. (Read on here how to secure the original images and how to keep them accessible / viewable in the admin for logged in users.) So in the second episode we want to support sites that need a more individual handling of images, including different output sizes and different cropped parts from an original image. Also we want to show a watermark in the bottom right corner in a 200px width, regardless of the width of the image variation. 1) Setup our site with a new overlay image 1.1) Create a new PNG image of 400 px width and 140 px height. Give it a half transparent background-color (40 - 60 percent opacity) and add some none transparent text over it. The text should be more then in the double size as you want to see it in the output on your site. For example like this one: 1.2) Upload it into the centralized image field (called setting_watermark in the previous episode) 2) Lets update our watermark function in site/ready.php 2.1) We now cannot any longer watermark the original images at first, because we don't know the exact final output dimensions and also not the final (maybe cropped) parts of the variations. Therefore we will work with the pageimage objects as usual and add our call to the watermark method as LAST action to each pageimage that should get a watermark overlay. $image = $page->images->first(); $variation = $image->crop('some settings here')->width(800)->wm(); ?> <img src='<?=$variation->url?>' alt='<?=$variation->description?>' /> So we will rewrite our function to suite our new needs. The first part can be taken mainly unchanged from the first episode: /** * Example Pageimage Hook for watermarking functionality, * adds a new method to Pageimage objetcs named wm. * Used in a small tutorial series in the ProcessWire forums * https://processwire.com/talk/topic/25752-tutorial-how-to-add-a-site-wide-optional-watermarking-method-to-all-pageimages/ * * @version 0.0.2 * */ $this->addHook('Pageimage::wm', function(HookEvent $event) { // get the image out of the event object $finalImage = $event->object; // this is no longer the $originalImage from episode 1 !! // access the field of the transparent watermark overlay image in a robust way, // regardless if it is set to 1 image or multiple images, and if it has changed // in this regard since we wrote this hook function $watermarkImages = wire()->pages->get('id=1')->getUnformatted('setting_watermark'); // check if the imagefield exists and it at least contain one image, than fetch it if(!$watermarkImages || 0 == count($watermarkImages)) { // return the unmodified original image to do not break our front end site $event->return = $finalImage; // inform the admin about the missing watermark overlay, (or do something other useful) wireMail('admin@example.com', 'noreply@example.com', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE'); wireLog('errors', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE'); // stop further execution return; } 2.2) Now lets have a short stop and think over. What do we want to achieve? We want create watermarked image variations and protect the unwatermarked images. Unwatermarked images are the original images and the intermediate variations that are created before we add an overlay to them. So in this situation, when we would following the regular image processing chain, we would create a variation with the resized and / or cropped version and after that, a watermarked variation, that we want to send to the browsers: original image: basename.jpg intermediate: basename.800x0.jpg watermarked: basename.800x0.-pim2-wm.jpg This would let all intermediate images unsafe in public scope, for everyone who knows a bit about the PW image processing routines. So the best solution would be to create the intermediate variations, watermark them and restore with the intermediate filename, not a filename that reflects that different processing step. This sounds fine, and indeed it is, with only one thing that we have to solve later: How can we detect if the current version is a watermarked (final) variation, or a unwatermarked "real" intermediate variation? 2.3) Following we rewrite the function from the first episode. First we have to check the incoming image, mainly its dimensions and if fits fine with the watermark sizes: // as we will overwrite this image with a watermarked version, // we have to make sure that this really is a variation and NOT an original image $isOriginal = null == $finalImage->getOriginal(); if($isOriginal) { // throw an exception, as this must be a bug in our code throw new WireException('Called a watermark method for final variation images on a original image!'); return; } // inspect the given image $ii = new ImageInspector(); $info = (object) $ii->inspect($finalImage->filename)['info']; // our preferred watermark width is 200px, so lets check if it fits into the variation if(200 >= $info->width) { // does not fit, is it a portrait oriented image with more then 300 px height? if(200 < $info->height) { // ok, we have to rotate our watermark -90 degree to make it fit to the bottom right $pngAlphaImage = $watermarkImages->first()->width(200)->pim2Load('rot270')->rotate(270)->pimSave(); } else { // the variation is to small for useful watermarking, we will leave and output it as is $event->return = $finalImage; return; } } else { // the width fits, so get a watermark image of 200px $pngAlphaImage = $watermarkImages->first()->width(200); } // now lets apply the watermark to our final variation, // this has to be done a bit different than we have done in the first episode. // The difference is, that we previously created another intermediate variation. // Now we want to avoid this, as it would make our watermarking processing nearly useless // in regard of protecting the unwatermarked images // we invoke the Pageimage Manipulator in a way that let us "overwrite" the loaded image, // what is not possible within its default processing $im = new \PageImageManipulator02(); $im = $im->imLoad($finalImage->filename, ['targetFilename' => $finalImage->filename])->setTargetFilename($finalImage->filename); $filename = $im->watermarkLogo($pngAlphaImage, 'SE', 0)->save(); $success = $finalImage->filename == $filename; // the imLoad()->save() process returns the filename of the processed image on success // $watermarkedImage = $finalImage; // this just should visualize what has happen in the black box :-) // With the previous episode, we had to return the watermarked variation and therefore had to replace the event object with it: // $event->return = $watermarkedImage; // But here, in fact we have overwritten the discfile that belongs to our incoming image object, // so there is no NEW image object that we have to change with the initial one! $event->return = $finalImage; }); 2.4) So, now we nearly have all together, but not how we can detect if a intermediate variation already has become a watermarked (final) version. Therefore the watermarking process is constantly executed again, with every view call now! So, what options are available to store the variations state for read / write in the processing chain? Into the DB? (has to be implemented first, and has to be cleared whenever an image and or its variations gets removed from the system) Into a sidecar file? (has to be implemented first, and also has to be cleared whenever an image and or its variations gets removed from the system) Into the variation file itself? (can be done via IPTC-data, but only for JPEGs) We also have since version 3.0.164 the possibility to store additional information for images & files into the DB. But this is only useful for the original image (or the complete group of original image and all its variation files), and not for individual single variation files. For this example we will go with the IPTC-data and take a simple helper class, that encapsulates this processes for us. For simplicity in this example, we also copy its code into the ready.php file. 2.5) Now we add the tracking into our function from above: ... // as we will overwrite this image with a watermarked version, // we have to make sure that this really is a variation and NOT an original image $isOriginal = null == $finalImage->getOriginal(); if($isOriginal) { // throw an exception, as this must be a bug in our code throw new WireException('Called a watermark method for final variation images on a original image!'); return; } // also we have to check if it already got watermarked, what we cannot get from the pageimage objects hirarchy // (that also is reflected in the filenames), as we have or will obfuscate(d) it: // read from IPTC tag if it is already processed $iptc = new hnReadWriteIptc($finalImage->filename); $isWatermarked = (bool)$iptc->readTag('isWatermarked'); if(!$isWatermarked) { ... So, if it is NOT watermarked, we will do it now with the code from our already built function. The only addition is to store the successful processing into the IPTC data, so that it is known with the next view call: ... // write our successful processing into our dedicated IPTC field to avoid repetitive processing $iptc->writeTag('isWatermarked', '1'); $iptc->writeIptcIntoFile(); } $event->return = $finalImage; }); 3) Our final code in the site/ready.php looks like this now: <?php namespace ProcessWire; /** * Example Pageimage Hook for watermarking functionality, * adds a new method to Pageimage objetcs named wm. * Used in a small tutorial series in the ProcessWire forums * https://processwire.com/talk/topic/25752-tutorial-how-to-add-a-site-wide-optional-watermarking-method-to-all-pageimages/ * * @version 0.0.2 * */ $this->addHook('Pageimage::wm', function(HookEvent $event) { // get the image out of the event object $finalImage = $event->object; // this is no longer the $originalImage from episode 1 !! // access the field of the transparent watermark overlay image in a robust way, // regardless if it is set to 1 image or multiple images, and if it has changed // in this regard since we wrote this hook function $watermarkImages = wire()->pages->get('id=1')->getUnformatted('setting_watermark'); // check if the imagefield exists and it at least contain one image, than fetch it if(!$watermarkImages || 0 == count($watermarkImages)) { // return the unmodified original image to do not break our front end site $event->return = $finalImage; // inform the admin about the missing watermark overlay, (or do something other useful) wireMail('admin@example.com', 'noreply@example.com', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE'); wireLog('errors', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE'); // stop further execution return; } // as we will overwrite this image with a watermarked version, // we have to make sure that this really is a variation and NOT an original image $isOriginal = null == $finalImage->getOriginal(); if($isOriginal) { // throw an exception, as this must be a bug in our code throw new WireException('Called a watermark method for final variation images on a original image!'); return; } // also we have to check if it already got watermarked, what we cannot get from the pageimage objects hirarchy // (that also reflects in the filenames), as we have or will obfuscate(d) them: // read from IPTC tag if it is already processed $iptc = new hnReadWriteIptc($finalImage->filename); $isWatermarked = (bool)$iptc->readTag('isWatermarked'); if(!$isWatermarked) { // inspect the given image $ii = new ImageInspector(); $info = (object) $ii->inspect($finalImage->filename)['info']; // our preferred watermark width is 200px, so lets check if it fits into the variation if(200 >= $info->width) { // does not fit, is it a portrait oriented image with more then 300 px height? if(200 < $info->height) { // ok, we have to rotate our watermark -90 degree to make it fit to the bottom right $pngAlphaImage = $watermarkImages->first()->width(200)->pim2Load('rot270')->rotate(270)->pimSave(); } else { // the variation is to small for useful watermarking, we will leave and output // it as is $event->return = $finalImage; return; } } else { // the width fits, get a watermark image of 200px $pngAlphaImage = $watermarkImages->first()->width(200); } // now lets apply the watermark to our final variation, // this has to be done a bit different than we have done in the first episode. // The difference is, that we previously created a intermediate variation. // Now we want to avoid this, as it would make our watermarking processing nearly useless // in regard of protecting the unwatermarked images // we invoke the Pageimage Manipulator in a way that lets us overwrite the loaded image, // what is not possible within its default behave $im = new \PageImageManipulator02(); $im = $im->imLoad($finalImage->filename, ['targetFilename' => $finalImage->filename])->setTargetFilename($finalImage->filename); $filename = $im->watermarkLogo($pngAlphaImage, 'SE', 0)->save(); $success = $finalImage->filename == $filename; // the imLoad()->save() process returns the filename of the processed image on success // $watermarkedImage = $finalImage; // this just should visualize what has happen in the black box :-) // to return the watermarked variation, // we have to replace the event object with our watermark variation // $event->return = $watermarkedImage; // But infact we have overwritten the discfile that belongs to our image object, // so there is no NEW imageobject that we have to change with the initial one // write our successful processing into our dedicated IPTC field to avoid repetitive processing $iptc->writeTag('isWatermarked', '1'); $iptc->writeIptcIntoFile(); } $event->return = $finalImage; }); Now we can call our watermarked images like this: $image = $page->images->first(); $variation = $image->width(800)->wm(); ?> <img src='<?=$variation->url?>' alt='<?=$variation->description?>' /> Thanks for reading! ?
    2 points
  5. AdminStyleRock Easily style your ProcessWire backend with two simple settings: Or via RockMigrations: $rm->installModule("AdminStyleRock", [ 'rockprimary' => '#0069B4', 'logo' => '/site/templates/img/kollar.svg', ]); ----------- Background: As of PW 3.0.179 we have a new style in AdminThemeUikit called "rock" style. This thread is here to report issues or ideas for improvement. The goal of the rock style is to make it as easy as possible to adapt your backend to the CI of your client. That's why it uses only ONE single main color and keeps all other design elements in a neutral grey. Download & Docs: https://github.com/baumrock/AdminStyleRock Here is an example screenshot using default uikit colors and a custom base font:
    1 point
  6. Hey folks! I'm happy to finally introduce a project I've been working on for quite a while now: it's called Wireframe, and it is an output framework for ProcessWire. Note that I'm posting this in the module development area, maily because this project is still in rather early stage. I've built a couple of sites with it myself, and parts of the codebase have been powering some pretty big and complex sites for many years now, but this should still be considered a soft launch ? -- Long story short, Wireframe is a module that provides the "backbone" for building sites (and apps) with ProcessWire using an MVC (or perhaps MVVM... one of those three or four letter acronyms anyway) inspired methodology. You could say that it's an output strategy, but I prefer the term "output framework", since in my mind the word "strategy" means something less tangible. A way of doing things, rather than a tool that actually does things. Wireframe (the module) provides a basic implementation for some familiar MVC concepts, such as Controllers and a View layer – the latter of which consists of layouts, partials, and template-specific views. There's no "model" layer, since in this context ProcessWire is the model. As a module Wireframe is actually quite simple – not even nearly the biggest one I've built – but there's still quite a bit of stuff to "get", so I've put together a demo & documentation site for it at https://wireframe-framework.com/. In addition to the core module, I'm also working on a couple of site profiles based on it. My current idea is actually to keep the module very light-weight, and implement most of the "opinionated" stuff in site profiles and/or companion modules. For an example MarkupMenu (which I released a while ago) was developed as one of those "companion modules" when I needed a menu module to use on the site profiles. Currently there are two public site profiles based on Wireframe: site-wireframe-docs is the demo&docs site mentioned above, just with placeholder content replaced with placeholder content. It's not a particularly complex site, but I believe it's still a pretty nice way to dig into the Wireframe module. site-wireframe-boilerplate is a boilerplate (or starter) site profile based on the docs site. This is still very much a work in progress, but essentially I'm trying to build a flexible yet full-featured starter profile you can just grab and start building upon. There will be a proper build process for resources, it will include most of the basic features one tends to need from site to site, etc. -- Requirements and getting started: Wireframe can be installed just like any ProcessWire module. Just clone or download it to your site/modules/ directory and install. It doesn't, though, do a whole lot of stuff on itself – please check out the documentation site for a step-by-step guide on setting up the directory structure, adding the "bootstrap file", etc. You may find it easier to install one of the site profiles mentioned above, but note that this process involves the use of Composer. In the case of the site profiles you can install ProcessWire as usual and download or clone the site profile directory into your setup, but after that you should run "composer install" to get all the dependencies – including the Wireframe module – in place. Hard requirements for Wireframe are ProcessWire 3.0.112 and PHP 7.1+. The codebase is authored with current PHP versions in mind, and while running it on 7.0 may be possible, anything below that definitely won't work. A feature I added just today to the Wireframe module is that in case ProcessWire has write access to your site/templates/ directory, you can use the module settings screen to create the expected directories automatically. Currently that's all, and the module won't – for an example – create Controllers or layouts for you, so you should check out the site profiles for examples on these. (I'm probably going to include some additional helper features in the near future.) -- This project is loosely based on an earlier project called pw-mvc, i.e. the main concepts (such as Controllers and the View layer) are very similar. That being said, Wireframe is a major upgrade in terms of both functionality and architecture: namespaces and autoloader support are now baked in, the codebase requires PHP 7, Controllers are classes extending \Wireframe\Controller (instead of regular "flat" PHP files), implementation based on a module instead of a collection of drop-in files, etc. While Wireframe is indeed still in a relatively early stage (0.3.0 was launched today, in case version numbers matter) for the most part I'm happy with the way it works, and likely won't change it too drastically anytime soon – so feel free to give it a try, and if you do, please let me know how it went. I will continue building upon this project, and I am also constantly working on various side projects, such as the site profiles and a few unannounced helper modules. I should probably add that while Wireframe is not hard to use, it is more geared towards those interested in "software development" type methodology. With future updates to the module, the site profiles, and the docs I hope to lower the learning curve, but certain level of "developer focus" will remain. Although of course the optimal outcome would be if I could use this project to lure more folks towards that end of the spectrum... ? -- Please let me know what you think – and thanks in advance!
    1 point
  7. Hi there, I'm starting a small series of tutorials here. The first one(s) deal with the topic "How can I add a watermark to all pageimages of a site?" first episode "Tutorial how to add a site wide optional watermarking method to all pageimages" second episode "Second Episode: "How can I add a watermark to all pageimages of a site?"" This is targeted to all, - beginners, intermediate, pros, - but mainly to interested PW lovers. The fictitious starting situation could be that a website owner has been creating beautiful photos for many years and would like to show them on his site in higher output sizes. A reference to real people or events does not exist, or would be "purely coincidental". Could someone please tell @Rob(AU) about this. ? This first episode shows a really straight and forward solution that could be an answer to the question "How can I get things be done?". We will create a PHP function that will give back a watermarked variation of every pageimage we put into it. We don't want bother our self to much with coding or image manipulation stuff. So for this first example we will setup our site with a single centralized image field that can contain one PNG image that should be used as our alpha transparency overlay for all watermarked image variations. Additionally to that, we install a PW third party module that does the image manipulation stuff. I will use the Page Image Manipulation module for this, because I know it very well. There are also *other good solutions in the PW ecosystem and if you would like you can add and use every existing PHP library that can assist you, or write your own individual low level code for that. But that's not our topic here. We want to get things done. Lets start! 1) Create a single centralized image field somewhere on a settings page if you have one. If your site doesn't has one, because you haven't had a need for that til now, the homepage may be a good place too. If you go with the homepage, but for other situations too, it may be a good idea to separate the overlay image input field from other content you have on that page. 1.1) Create an image field that should contain one file, and only of type PNG 1.2) Create a fieldset tab 1.3) Add both to the template of your choice 2) Add the Page Image Manipulator module to your site ... 2.1) ... by going to your modules section in the admin, select the tab "New" and add the Modules Classname under "Add Module From Directory": PageImageManipulator 2.2) Download and install it. 2.3) Go to the modules site tab and scroll down to the position where you find the entries for a Pageimage Manipulator 1 and a Pageimage Manipulator 2. There you can savely uninstall the legacy version 1 that is only needed for PW version prior to 2.6. 3) Provide a PNG overlay image. For this example we want use a 2000 x 2000 px transparent PNG image with our watermark sign or watermark text. If you don't have one ready but have an image manipulation program on your local machine at hand that excepts photoshop actions, you can download one here for fast creation: photoshop_action_PW-png-creations.zip 3.1) Create a new image 2000px x 2000px with a transparent background 3.2) Add some meaningful text at a position you like. If you want to use the PS action, don't forget to rasterize all vector text before starting it. 3.3) Regardless if you used the PS action or created some nice overlay in another way, you should set the opacity of the final image to something between 20 and 40 percent. You may have to test this out for a production version. But now we want to get things done. Save the final version and ... 3.4) Upload it into the centralized image field in your site! 4) Create a PHP function that encapsulates the watermark overlay process and outputs a finished pageimage as a variation. To get a go here without messing up our site, we can create a test.php file as sibling of PWs index.php. We will *boostrap PW there and get full access to the API site this way: <?php namespace ProcessWire; include __DIR__ . '/index.php'; function ourWatermarkTestfunction(Pageimage $image) { return $watermarkedImage; } Let the file operating in the PW namespace, boostrap the PW API and our barebone function. We want to pass in a pageimage and we want to get out a pageimage that is a watermarked variation of the source pageimage. If we want to test what we have so far, we would fetch us an image from a page we know it has one and pass it into the function: <?php namespace ProcessWire; include __DIR__ . '/index.php'; function ourWatermarkTestfunction(Pageimage $originalImage) { $watermarkedImage = $originalImage; return $watermarkedImage; } $image = $pages->get('[your selector here to a well known page that has an images field called images]')->images->first(); $variation = ourWatermarkTestfunction($image); $variation = $variation->width(800); echo "<img src='{$variation->url}' alt='{$variation->description}' />"; We tweaked our function to pass us the input image as output. And we echo out it as a HTML image. If this is working as expected, we can start to do code the main part of our function. We will use the module Pageimage Manipulator for that and referring to its description page, when we scroll down to the method called watermarkLogo, it tells us how we can use it. watermarkLogo($pngAlphaImage, $position='center', $padding=2) It want to have one mandatory param, the transparent PNG overlay image. Optionally it can take params for positioning the overlay. For our test we will use the defaults and as they are optional arguments, we don't need to call them. Referring to the PIM2 API, we have to start the process by calling pim2Load($prefix, $param2=optional, $param3=optional) And at the end we have to call pimSave() Putting this together we will get this: function ourWatermarkTestfunction(Pageimage $originalImage) { $watermarkedImage = $originalImage->pim2Load('wm')->watermarkLogo($pngAlphaImage)->pimSave(); return $watermarkedImage; } So, this will produce an error as we have not specified what $pngAlphaImage is. It should be our site wide overlay image that we have stored at a well known place, for example on our homepage. Also we want to apply a check if we really get a Pageimage from there, to avoid unhandled errors if for whatever reason the image gets deleted by accident at some time in the future. function ourWatermarkTestfunction(Pageimage $originalImage) { // get the field of the transparent watermark overlay image in a robust way, // regardless if it is set to 1 image or multiple images, and if it gets changed or not in the future $watermarkImages = wire()->pages->get('id=1')->getUnformatted('setting_watermark'); if(!$watermarkImages) { // return the unmodified original image to do not break our front end site return $originalImage; } // check if it at least contain one image, than fetch it if(0 == count($watermarkImages)) { // return the unmodified original image to do not break our front end site return $originalImage; } $pngAlphaImage = $watermarkImages->first(); // is the same as wire()->pages->get('id=1')->getUnformatted('setting_watermark')->first() // now let the module process our watermarking and save it into a variation $watermarkedImage = $originalImage->pim2Load('wm')->watermarkLogo($pngAlphaImage)->pimSave(); // return the watermarked variation return $watermarkedImage; } Lets have a visually check if all went well: $image = $pages->get('[your selector here to a well known page that has an images field called images]')->images->first(); $variation = ourWatermarkTestfunction($image); $variation = $variation->width(800); ?> <img src='<?=$variation->url?>' alt='<?=$variation->description?>' /> Now we should see our watermarked variation in the same dimensions as the original is. That's fine and it's time to leave the test and implement that into our custom site API. We will add a hook to the Pageimage object that we want call 'wm' and that does exactly what we have created here. 5) Open your site/ready.php and add the following hook into it: <?php namespace ProcessWire; $this->addHook('Pageimage::wm', function(HookEvent $event) { }); Now we can call on every Pageimage the new method wm: $image->wm->width(500) to get a watermarked and 500px width resized variation out. Ok, first we have to add our functions body into it. And we slightly have to change it a bit, because now it became a anonymous function of a HookEvent. Therefore it has not a own name anymore, and the input is not a Pageimage in the first time, but a HookEvent. (But in the end, it is a Pageimage, because it is a hooked event of a Pageimage. ?) /** * Example Pageimage Hook for watermarking functionality, * adds a new method to Pageimage objetcs named wm. * Used in a small tutorial series in the ProcessWire forums * https://processwire.com/talk/topic/25752-tutorial-how-to-add-a-site-wide-optional-watermarking-method-to-all-pageimages/ * * @version 0.0.1 * * @var HookEvent */ $this->addHook('Pageimage::wm', function(HookEvent $event) { // get the image out of the event object $originalImage = $event->object; // access the field of the transparent watermark overlay image in a robust way, // regardless if it is set to 1 image or multiple images, and if it has changed // in this regard since we wrote this hook function $watermarkImages = wire()->pages->get('id=1')->getUnformatted('setting_watermark'); // check if the imagefield exists and it at least contain one image, than fetch it if(!$watermarkImages || 0 == count($watermarkImages)) { // return the unmodified original image to do not break our front end site $event->return = $originalImage; // inform the admin about the missing watermark overlay, (or do something other useful) wireMail('admin@example.com', 'noreply@example.com', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE'); wireLog('errors', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE'); // stop further execution return; } $pngAlphaImage = $watermarkImages->first(); // is the same as wire()->pages->get('id=1')->getUnformatted('setting_watermark')->first() // now let the module process our watermarking and save it into a variation $watermarkedImage = $originalImage->pim2Load('wm')->watermarkLogo($pngAlphaImage)->pimSave(); // to return the watermarked variation, // we have to replace the event object with our watermark variation $event->return = $watermarkedImage; }); Now we can call our watermarked images like this: $image = $page->images->first(); $variation = $image->wm()->width(800); ?> <img src='<?=$variation->url?>' alt='<?=$variation->description?>' /> Now all looks fine in the first line. But there is some room for improvements also in this basic "get the things done" solution. I keep this for one of the next episodes, where we can dive a little bit into image debugging and / or create a more advanced version of the image watermarking function, maybe as a PW module. Thanks for reading! ? TL;DR *pageimage https://processwire.com/api/ref/pageimage/ *boostrap https://processwire.com/docs/front-end/include/ *image modules https://processwire.com/modules/category/photo-video/ *hooks https://processwire.com/docs/modules/hooks/ *hook event__https://processwire.com/api/ref/hook-event/
    1 point
  8. I think your reasoning is sound. Especially for blocks that are re-used across pages (which I didn't have in mind).
    1 point
  9. I see. In that case creating a custom field would probably be best and have little overhead if it's autoloaded. What's the reasoning behind storing the data on the parent and not on the children? Performance? Storing it on the children, you could use the `$page->meta()` api and avoid the need for hooks since that should be cloned alongside the page. It currently only allows associative arrays and might have a performance penalty as well.
    1 point
  10. Could you explain what your goal is? I mean — you're already handling dependencies via Composer, so that's a good start at least ? If you want the module itself to be installable via Composer, the approach I'd currently recommend is detailed here: https://github.com/wireframe-framework/processwire-composer-installer. Change the "type" in your composer.json to "pw-module" and add wireframe-framework/processwire-composer-installer to your requires and that's just about it. In case you were wondering, ProcessWire doesn't currently have a way to handle Composer dependencies when a module is installed via Admin. Module with dependencies will either a) need to be installed the regular way and then the user has to run composer install manually, or b) installed via Composer (see processwire-composer-installer) in which case dependencies are automatically handled. ... or you could bundle all dependencies in the Git repository itself. Somewhat crude approach perhaps, but also the easiest one for most users of your module.
    1 point
  11. Version 0.21.0 released: ### Added - Hookable method MethodPropsTrait::getMethodPropCacheName(string $name, string $context). Note that when hooking into this method one should refer to the object that implements the trait, such as a specific Controller class. ### Changed - Include language ID in persistent cache name generated by MethodPropsTrait for cacheable methods. @Zeka, thanks for bringing the lack of multi-language support for cache names up. While testing I noticed that a site I've been working on recently was in fact also affected. Not a huge deal in this case but it could've caused some confusion. For the record: I ended up just adding the language ID to the key. If LanguageSupport is not installed it'll be a blank value, but that doesn't really matter ?
    1 point
  12. ProcessWire 3.0.180 contains 20 commits containing various minor new features, issue resolutions and pull requests. While there's no single major feature to write a big blog post around, combined there are a lot of worthwhile and useful updates so this version is definitely worth updating to. More details can be found in the dev branch commit log and at ProcessWire Weekly (issue #370 covered an addition to our $files API var). Yesterday the forums were running a little slow because we had our yearly DDOS’er pay the site a visit once again (remember last time?), and from an apparently unlimited supply of IP addresses around the world this time. We shut down the forums to users that weren't logged in while the load was high. Actually, it does this automatically now. We also updated the forums from using memcached to AWS Redis, which should also help as a nice upgrade for the forums. Big thanks to @Pete and @Jan V. for setting it up and keeping everything running smoothly. I'll keep it short today because it's supposed to rain here all weekend, so I'm going to spend some time outside while I can. Thanks for reading and have a great weekend!
    1 point
×
×
  • Create New...