Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Posts posted by gebeer

  1. Hi, I'm facing a strange issue with priority values being output with colon (0,5) instead of period (0.5) which I guess is wrong.

    On some servers PW issues a warning to translate the locale setting:


    I have a site with a single language (German) and language support enabled to have the backend translated to German.
    So I translated the locale setting to de_DE.UTF-8


    But now sitemap items that are generated through a hook will output 0,5 (which is correct for German locale). Other pages in the sitemap output correctly like 0.5.

    I have automatic sitemap generation disabled because I update it manually whenever some data changes that comes from an external XML and is converted to virtual pages on runtime that do not get saved to the DB.

    My code for adding those virtual page entries to the sitemap

        public function updateXmlSitemap()
            $config = $this->wire('modules')->getConfig('SeoMaestro');
            $items = $this->stellenangeboteXMLToPageArray(); // results in array of virtual pages
            $entries = array();
            foreach ($items as $item) {
                $entry = (new SitemapItem())
                    ->set('loc', $config['baseUrl'] . $item->url)
                    ->set('lastmod', date('c'), time())
                    ->set('priority', (float) 0.7) // casting explicitly to float doesn't help
                    ->set('changefreq', 'daily');
                $entries[] = $entry;
            $this->addHookAfter('SeoMaestro::sitemapItems', function (HookEvent $event) use ($entries) {
                $event->return = array_merge($event->return, $entries); // add my entries to the sitemap
            $manager = new SitemapManager($config);
            try {
                $sitemap = $manager->generate($this->wire('config')->paths->root . $config['sitemapPath']);
                if (!$sitemap) {
                    $this->wire('log')->save(strtolower($this->className), 'Could not generate sitemap');
                } else {
                    $this->wire('log')->save(strtolower($this->className), 'sitemap generated');
            } catch (\Throwable $th) {
                $this->wire('log')->save($this->className, 'Error generating sitemap' . $th->getMessage());

    I don't know why the items added to the sitemap through my hook produce different output (0,5) from the items that are generated by the module (0.5).

    Could you make sure in the module code that the priority value is always being rendered as a float value, no matter what locale setting? That would be awesome.

  2. 11 hours ago, Jens Martsch - dotnetic said:

    The newest version of Klaro gives you the option if the CSS is included or you provide your own CSS. This is based on my PR.

    How do you actually build a version without css? I cloned the repo and added this to the scripts section of package.json and then run npm run makenocss

        "makenocss": "cross-env APP_ENV=production cross-env APP_VERSION=$(git tag --points-at HEAD) cross-env APP_COMMIT=$(git rev-parse HEAD) cross-env SEPARATE_CSS=true webpack --config webpack.config.js"

    This will build a klaro-no-css.js inside dist.

    Is there a simpler way passing the SEPARATE_CSS flag to the make script?

  3. 16 hours ago, Sergio said:

    Another question, do you know if there's a way to have a granular control on the scripts loaded by Google Tag Manager?

    With klaro consent manager you can gain control over the scripts loaded by GTM. See this issue. (I'm not affiliated with that project in any way, just using it on a couple of sites)

    It is implemented via custom callback functions for each app that is managed by the consent manager. @joshua Maybe you could go a similar route to make configuration more flexible and tweakable? And thanks for putting this together!

    And a suggestion for improvement: The type="optin" attribute is not a valid script attribute. So W3C Validator will not like it. You could use text/plain instead. That is not very semantic but could help to pass validator tests...

    • Like 3

  4. Hello all,

    wasn't sure where to put this, so it goes in General section.

    Ryan shows a hook that we can use to mirror files on demand from live server to development environment to be up to date with the files on the server without having to download complete site/assets/files folder.

    I just implemented this but had problems getting files to load from a site in development that is secured with user/password via htaccess.

    First I tried to use WireHttp setHeader method for basic authentication like this

        function mirrorFilesfromLiveServer(HookEvent $event)
            $config = $event->wire('config');
            $file = $event->return;
            if ($event->method == 'url') {
                // convert url to disk path
                $file = $config->paths->root . substr($file, strlen($config->urls->root));
            if (!file_exists($file)) {
                // download file from source if it doesn't exist here
                $src = 'http://mydomain.com/site/assets/files/';
                $url = str_replace($config->paths->files, $src, $file);
                $http = new WireHttp();
                // basic authentication
                $u = 'myuser';
                $pw = 'mypassword';
                $http->setHeader('Authorization: Basic', base64_encode("$u:$pw"));
                $http->download($url, $file);

    But, unfortunately this didn't work.

    So now I am using curl to do the download. My hook function now looks like this

        function mirrorFilesfromLiveServer(HookEvent $event)
            $config = $event->wire('config');
            $file = $event->return;
            if ($event->method == 'url') {
                // convert url to disk path
                $file = $config->paths->root . substr($file, strlen($config->urls->root));
            if (!file_exists($file)) {
                // download file from source if it doesn't exist here
                $src = 'http://mydomain.com/site/assets/files/';
                $fp = fopen($file, 'w+'); // init file pointer
                $url = str_replace($config->paths->files, $src, $file);
                $u = 'myuser';
                $pw = 'mypassword';
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_TIMEOUT, 50); // crazy high timeout just in case there are very large files
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_USERPWD, "$u:$pw"); // authentication
                curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); // authentication
                curl_setopt($ch, CURLOPT_FILE, $fp); // give curl the file pointer so that it can write to it
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
                $data = curl_exec($ch);

    Now I can load files and images from the htaccess protected development server 🙂

    If anyone knows how to get this to work with WireHttp, please let me know. Thank you.

    • Like 2

  5. I am having a different issue. With v1.2.0. I get this warning: 
    array_key_exists() expects parameter 2 to be array, null given
    File: .../EmailObfuscation/EmailObfuscation.module:352

    352 if(!is_array($options) && !array_key_exists('pageStack', $options)) {
              return false;

    If $options passes the first test, it is not an array. The second test checks for array_key_exists in a non-array. Hence the warning.

    The error is being triggered when $options is null.

    As a temp workaround I amended the if statement to read

    if(is_array($options) && !array_key_exists('pageStack', $options)) {
    	return false;

    Not sure though if this is correct. Maybe you wanted to return false when $options is not an array, too?


  6. Instead of having extra fields and saving extra data, you could make use of the $page->references() method, I mentioned above. You could utilize this method inside a ProcessPageEdit::buildFormContent hook and add a Markup field that holds the titles (and even links) of the referenced pages. Just an idea.

  7. 54 minutes ago, bernhard said:

    t would be very easy to create a RockDatetime field based on the core Datetime field but waking up having a RockDatetime object instead of a timestamp. Maybe you want to experiment with that and create a PR?

    I thought I'd just use your new inputfield type 🙂 Won't have time for implementing this before April. If I see room for improvement on your module, I am happy to make a PR. Thanks again!

  8. Since modern browsers support flex and grid and most CSS3 specs, I also moved from using frameworks like BS to setting up things manually with my own, reusable scss partials and the JS libs that I need for a project. Also trying to move more and more to vanilla JS and kick jQuery. This way I get more streamlined assets. If I need to support old browsers (mainly IE11), I write some specific extra CSS to cater for them if need be.

    • Like 1
    • Thanks 1

  9. Did you have a look at $page->references() method? This gives you all pages that reference this page. In the page edit screen you can see those in the "Settings" tab under "What pages link to this page". With this method available in your template php maybe you don't even need your hook.

    And there is @Robin S's module ConnectPageFields that handles those cases.

    You might also want to take a look at @Martijn Geerts' FieldPageSync Module that also does something similar.

  10. 1 hour ago, bernhard said:

    I've put a lot of effort into developing the RockDatetime module. It is already available on Github and has lots of examples and docs in the readme: https://github.com/BernhardBaumrock/RockDatetime

    Thank you so much for all your efforts in putting this together! I'll be using this soon to replace date range logic in 2 live projects that deal with events.

    • Like 1

  11. To find all pages where the repeater field word_object has a field this_word with value apple you can use subfield selectors

    $pageArray = $pages->find("word_object.this_word=apple")

    This will return a PageArray with all those pages.

    Now to get all the word_object repeater fields from this PageArray, you can use the  WireArray explode method

    $repeatersArray = $pageArray->explode("word_object")

    This will return an array with all the repeater fields. You can now foreach through this array and output whatever you need.

    You could also chain this to a single operation

    $repeatersArray = $pages->find("word_object.this_word=apple")->explode("word_object")


    • Like 4

  12. 5 hours ago, teppo said:

    Overall there are very few cases where the title attribute should be used

    Thanks for that link! An agency I'm sometimes working for wants to have title attributes on all links, no matter what. They say it's for SEO. Sorry for getting offtopic.

    6 hours ago, bernhard said:
    • Show time input?
    • Show end input?

    I'd call them something like 'Input time' and 'Input end' because that is actually what you can do after clicking on them and is also like an instruction of what to do or what can be done.


    10 minutes ago, adrian said:

    I would recommend a full read of the recurme support thread

    That sure is a long read but well worth it.

    • Like 2

  13. 13 minutes ago, bernhard said:

    I've absolutely no experience in handling different timezones, so I'd be happy to get a quickstart or a good read for that topic

    This is really only necessary if you are dealing with user input of users from different time zones.
    You'd also have to know the timezone of the logged in user. For projects where I needed that, I had a field in the user template to save the timezone and did calculations based on that. It is hard to foresee how other people implement it and therefore in the fieldtype you would not know how to get the user timezone. Maybe in a hookable method that by default returns the local server timezone. Then people could hook into it and provide the user timezone only if it differs from the server timezone.
    The common base for calculation between different timezones is the unix timestamp. So the resulting timestamp for 01.01.2020 20:00 will be different, depending on what the timezone is. The DateTime class has the  setTimezone method which helps for conversion of DateTime objects between different timezones. Here's a quick read on the basics.

    • Like 1
    • Thanks 1

  14. That looks great so far, will be a really useful fieldtype!

    55 minutes ago, bernhard said:

    I think option 1 is cleaner and easier to use and develop, so I'll continue with this option

    I also prefer option 1. Much cleaner than having to involve yet another module.

    55 minutes ago, bernhard said:

    I'm of course already thinking of how this could be extended to support recurring events (date ranges) in the future... I'm not sure how to do that yet, but I think it could make a lot of sense to build this feature into this module

    This would be so awesome. Especially since the Recurme module seems to have passed away silently. Maybe you can get some inspiration from there on how to handle recurring stuff. I wouldn't include the whole render a calendar stuff. People who need it can always use some existing framework for that.

    55 minutes ago, bernhard said:

    I'm not sure if/how/when I can realease this module. I'm building it now for one project and want to see how it works first.

    Would be great if you could share the code pre-release on GH so people who are interested could collaborate.

    55 minutes ago, bernhard said:

    I wanted to share the status with you to get some feedback and maybe also get your experiences in working with dates and times or maybe working with recurring events

    I did some date manipulation in the past because I'm involved with quite a few sites that needed it. What I found most challenging is the timezone calculations. Also did some recurring stuff as far as I remember. What I found very helpful at the time for those tasks are the PHP DateTime, DatePeriod and Dateinterval classes. Haven't delved into it for some 3 years but remember that it actually was fun. I guess today I would use the recurr library.

    EDIT: As for the recurring events, I'd probably make this optional in the field settings and only present the inputs if needed.

    • Like 4

  15. 12 hours ago, bernhard said:

    I was tired of adding 6 different fields to an event-template just for storing the time range of the event...

    Great. Can't wait to see it (if you plan to release this) 🙂 Any plans for recurring events?

    • Like 1

  16. 53 minutes ago, ragnarokkr said:

    I just moved back to WordPress

    Sad to hear that. But can understand your frustration. People coming from WP are used to have new functionality installed with one click.


    54 minutes ago, ragnarokkr said:

    I really think that an out-of-the-box system to handle this case via Image field should be mandatory for a CMS like PW

    PW just uses a different approach here. And there are custom modules like Media Manager or ImageReference that can do what you need.


    55 minutes ago, ragnarokkr said:

    just some sort of merge of Image field's and ImageReference's logics to offer the power of the Image options (sizing, cropping, min/max sizes, etc) with the options of different sources

    That is exactly what ImageReference aims to do. I am sorry that it doesn't cater for all of your needs (yet), like descriptions for images from folders.

    59 minutes ago, ragnarokkr said:

    The rest should just be hooks, the developers could register to extend the functionalities.

    That would be what I meant with hiding the image page in the page tree. The link I provided contains code for such hooks. If you don't know how to put a hook together for your exact use case then describe the problem and I am sure someone will help you out here in the forums.

    • Like 1

  17. 19 hours ago, ragnarokkr said:

    As said, I need a system folder as a source in order to have a persistent and common path regardless the changes an admin could do in future to the page tree, so the one page isn't a viable solution in my case.

    Just an idea:  you could hide the image page from the page tree in the admin area so that users with certain roles cannot mess with it. Some code examples in this thread.
    EDIT: that would give you your persistent and common path under /site/assets/files/{imagepageID}/

  18. 7 hours ago, BitPoet said:

    I was thinking of combining the two. Have a toplevel Media Library somewhere and let ImageReference pull its images from that. Though I'm not familiar enough with the latter to judge if that would be a working solution.

    With Image Reference you can have all images on one page (that can be hidden in the tree). Then you set the ImageReference input field to pull images only from that page.

    On 2/3/2020 at 12:41 AM, ragnarokkr said:
    • image preview not (yet) responsive in edit page, or at least in my case it doesn't work as (I) expected;
    • no scrolling in image selection (widget expans a lot especially if the container is narrow);
    • no description available for the uploaded images.

    Please note that I already have pushed a fix 2 days ago for the responsive issue you posted on GH.
    The scrolling you are talking about is really only needed for rare edge cases like yours where the ImageRefenrence input field in the page edit screen is very narrow. Please understand that I will not cater for that edge case. You might want to rethink the layout of your gallery input in the page edit screen.
    If you need descriptions for your images, you can reference them from a hidden page (like mentioned above) instead of from a folder. If someone tries to remove an image from that page and that image is still being referenced somewhere else, the module will give a warning and will not allow to remove the image before all references to it were deleted. So this option could be a solution to your use case.

    • Like 1

  19. 11 hours ago, dragan said:

    I have added that folder after creating the field. Does that matter? Does the folder have to be there before you create an image reference field?

    It doesn't matter whether you create the folder before or after. The module will pick it up once it is there. If it is not there yet, you will get a warning. Once it is there, the warning normally goes away. If it is empty, you will get a warning to upload images.

    Can't reproduce your problem here on PW 3.0.145 PHP 7.2 But versions really shouldn't matter in that case. Did you install latest master?

    EDIT: just tested this on PW 3.0.149 and PHP 7.3.2 without problems.

    Where did you create the folder? It needs to be either in /site/assets/ or /site/templates/.

    Please try and comment out line 680 in FieldtypeImagereference.module and see if the warning message persists. I attached the error to both the field and globally so it is shown at the top of the page when you save the settings. Maybe this is the culprit in your case?

  20. I think, what you might be looking for is the 'Family' settings for templates. Here you can define, what child templates are allowed for a parent page with a specific template.

    So, for example, your parent page 'Blog' for your blog items might have the template 'blog' and the child pages (your blog entries) have the template 'blog-item'. In the template's 'Family' settings for template 'blog' you can define to only allow template 'blog-item' as child template. And in the template 'blog-item' you can define to only allow template 'blog' as parent template.

    Now when an editor adds a page to 'Blog' in the page tree, the new page will automatically get template 'blog-item' assigned.

    • Like 2

  21. New version v2.1.2 is out on github.

    This version fixes a problem with images inside a folder that have names not conform with file naming conventions.

    When the module loads images from a folder, it converts them to Pageimage objects. When images are added to a Pageimages object file names get sanitized automatically by PW. In my case this resulted in different file names inside the Pageimage object and on disk. Consequently, thumbnails and previews for those images could not be loaded. I fixed this by automatically renaming all folder images to match the sanitized name versions inside a Pagimage object. 

    This version also adds the ability to set values to this field via API. You can now do something like this to set a Pageimage object as new value to this fieldtype via API

    $p = $pages->get(1001);
    $image = $p->image; // returns a Pageimage object
    $p->set('imagereference', $image); // sets the Pageimage object to the ImageReference field. This gets converted to a JSON string internally for storage


    • Like 3

  22. 1 hour ago, flydev 👊🏻 said:

    And simply using $this->pages->findOne() inside Events can't do the job ?

    This does the job perfectly, indeed. Thanks a lot for that simple yet elegant solution.

    So all you need to add to site/api/events.php is

        public function findOne($selector, $options = array()) {
    		return $this->pages->findOne($selector, $options);


    • Like 1
  • Create New...