Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 03/05/2020 in all areas

  1. Use the function wireMail() or the $mail->new() to instantiate an E-Mail object, then ProcessWire will automatically look for other WireMail modules and instantiate one of them instead of the default WireMail object. You can also request a specific WireMail module by specifing it as an option. For example, for the Mailgun module, this should work: $mailgun = $mail->new(['module' => 'WireMailMailgun']); $mailgun instanceof WireMailMailgun; // true See the documentation for $mail->new().
    4 points
  2. Plenty of posts on the forum relating to Content Security Policy (CSP) and how to integrate it with Processwire. It's not too hard to implement a decent htaccess CSP that will get you a solid B+ at Mozilla Observatory. If you're after A+ it's a little harder because of all the back-end stuff... until you realize it's surprisingly easy. After a lot of testing, the easiest way I found was to specify only what is needed in the htaccess and then add your required CSP as a meta in your page template. Plenty of people have suggested similar. Works very easily for back-end vs front-end, but gets complicated if you want front page editing. Luckily, a little php will preserve back-end and front page editing capabilities while allowing you to lock down the site for anyone not logged in. None of this is rocket science, but CSPs are a bit of a pain the rear, so the easier the better, I reckon ? The only CSP I'd suggest you include in your site htaccess is: Header set Content-Security-Policy "frame-ancestors 'self'" The reason for this is you can't set "frame-ancestors" via meta tags. In addition, you can only make your CSP more restrictive using meta tags, not less, so leaving the back-end free is a solid plan to avoid frustration. Then in your public front-facing page template/s, add your desired Content Security Policy as a meta tag. Please note: your CSP should be the first meta tag after your <head>. For example: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Security-Policy" content="Your CSP goes here"> <!-- followed by whatever your normal meta tags are --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="format-detection" content="telephone=no"> If you haven't got Front Page Editing enabled, this works fine by itself. Just one extra step is needed to make sure you don't have to worry either way. The easiest way I found to allow both CSP and front page editing capabilities is the addition of a little php, according to whatever your needs are. Basically, if the user is a guest, throw in your CSP, if they're not do nothing. It's so simple I could have kicked myself when it finally dawned on me. I wish it had clicked for me earlier in my testing, but it didn't so I'm here to try to save some other person a little time. Example: <!DOCTYPE html> <html> <head> <?php if ($user->isGuest()): ?> <meta http-equiv="Content-Security-Policy" content="Your CSP goes here"> <?php endif; ?> <!-- followed by whatever your normal meta tags are --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="format-detection" content="telephone=no"> If you want it a bit more involved then you can add additional tests and be as specific as you like about what pages should get which CSP. For example, the following is what I use to expand the scope of the CSP only for my "map" page: <?php $loadMap = $page->name === "map"; ?> <!DOCTYPE html> <html> <head> <?php if ($user->isGuest()): ?> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'self'; manifest-src 'self'; form-action 'self'; font-src 'self' data: https://fonts.gstatic.com; frame-src 'self' https://www.youtube.com; img-src 'self' data:<?php echo ($loadMap) ? " https://maps.googleapis.com https://maps.gstatic.com" : ""; ?> https://www.google-analytics.com; script-src 'self' <?php echo ($loadMap) ? "https://maps.googleapis.com " : ""; ?>https://www.google-analytics.com https://www.googletagmanager.com; style-src 'self' <?php echo ($loadMap) ? "'unsafe-inline' https://fonts.googleapis.com" : ""; ?>"> <?php endif; ?> Hope this saves someone a little time testing. https://observatory.mozilla.org/analyze/bene.net.au
    1 point
  3. Tbh, I find this whole “virtual field” business somewhat unfortunate… The announcement of custom image fields filled me with joy, and I thought the idea of using templates seemed pretty ingenious (although I don’t like how it introduces magic strings into template names, and generally restricts their naming, and doesn’t allow multiple image fields to share a template. Feels icky to me. Why not have a template selector in the field settings?). However, I was disappointed to find that values are just serialized and dumped into the image-field table. Seems like this data is treated as some kind of second-class citizen. If the custom fields were stored in their own database columns, as suggested by using templates and fields, it would have been a trivial INSERT to migrate from the ImageExtra module. Now I needed to use the PW API to move values from one field to the next, which involves all kinds of voodoo behind the scenes. Wouldn’t it be much less work to just store a page reference with each image and have the custom image fields stored in their respective field-tables? Surely that way it would be easier to make everything play nicely with selectors and everything? Of course, I have to admit I don’t have a lot of MySQL experience. Maybe there are easy and performant and reliable ways to query serialized fields like this and I just need to read up a little ?
    1 point
  4. I solved this with a work around. I checked if a page was modified in the last hour. If it was modified, I did not run the function. If it was not modified in the last hour, I run the function. That way, I could set the LazyCron to fire "every30Seconds".
    1 point
  5. 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...
    1 point
  6. Anybody ever had horizontal scrollbars in the PW admin? It's a known issue and I've just pushed a fix for it to the PwQuickFixes module: https://github.com/BernhardBaumrock/PwQuickFixes/commit/4db6b4659692e3888a20ea89752fdce40d4425fe Before: After:
    1 point
  7. Sorry for wasting your time, I was friggin' blind : put <!--<img src='{$image->size(1600, 550, 100)->url}' alt='{$image->description}' width='1600' height ='550'>--> to <img src='{$image->size(1600, 550, 100)->url}' alt='{$image->description}' width='1600' height ='550'> and it works fine.
    1 point
  8. Just wanted to share another use case for $files->url() and $files->path() // old version function mirrorFilesfromLiveServer(HookEvent $event) { $config = $this->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(!is_file($file)) return; This example is taken from this recent post by @gebeer and it would be a lot better to read and maintain with the new methods: // new version function mirrorFilesfromLiveServer(HookEvent $event) { $file = $this->wire('files')->path($event->return); if(!is_file($file) return; In the old version he gets the filename from the $event. He then has to check for the $event->method, because in one case the file is a PATH and in the other it is a URL. That's why he has to modify $file if the method is "url"... And then he does what many of us do in such situations: Use string operations. They are not only ugly but also error prone: Think of different directory separators, missing or doubled slashes (eg /foo/bar//myfile.js or /foo/barmyfile.js). This was all not necessary if we had $files->path() and $files->url() ? See the second example. In one single $files->path() call all the complicated code from example 1 is obsolete. $files->path() returns the path of the file, no matter if it was provided as url or path. So simple, so beautiful.
    1 point
  9. Thanks, but not necessary. Pretty much all my modules get created because I have a need for them in work that I get paid to do, and it doesn't cost me anything to make them available for others to use too.
    1 point
  10. Thanks @Jens Martsch - dotnetic for reporting back!
    1 point
  11. Hey @ryan this sounds great ? Could you please have a look at https://github.com/BernhardBaumrock/RockDatetime and see if that might be something that find its way into the core? I think some solid date and time handling API would be a great addition to PW! RockDatetime was developed because I need it for a new module that I'm working on for dealing with date ranges. See this recent post from today about the latest additions: I'm especially talking about this post: https://processwire.com/talk/topic/23097-previewdiscussion-rockdaterange-fieldtype-inputfield-to-easily-pick-daterange-or-timerange/?do=findComment&comment=198191 It's neither well tested nore complete. But feel free to copy/paste/improve as much as you want ? I think having an API for dates and times would be a very logical addition to the PW API awesomeness ? I'm talking about things like this: // calculating FROM/TO for RockDaterange case 'hour': $from = new RockDatetime("{$obj->date} {$obj->time}:00:00"); if($isTo) $to = $from; else $to = $from->copy()->move("+1 hour"); break; // check if FROM starts at 00:00 on that day if($this->from->equals($this->from->firstOfDay()) ... // show modified date when different from created day $updated = new RockDatetime($page->getUnformatted("modified")); $date = "Zuletzt aktualisiert am ".$updated->format("%d.%m.%Y"); if($updated->sameDay($page->getUnformatted("created"))) $date = ""; // formatting $d = new RockDatetime("25.02.2020 14:00"); echo $d->format(); // 25.02.2020 14:00 echo $d->format("%A, %d.%m.%y (%H:%M Uhr)"); // Dienstag, 25.02.20 (14:00 Uhr) echo $d->format(['time' => "%H|%M|%S"]); // 25.02.2020 14|30|00 On a side note I want to ask you if you please could consider to have a look at this request: https://github.com/processwire/processwire-requests/issues/326 I'm struggling on almost all my module development with proper file path and url handling and I'm doing the implementations over and over again because I don't want to add a module dependency for that. This little thing should really be in the core! We've had some problems with windows/unix file path handling recently and it shows again how important it is to have the right tools at our hands without implementing those things on our own: PS: As I've started to build my first "real" Fieldtype module with custom DB schema I want to say thank you for that awesome piece of software that you've developed here! Unfortunately there are no docs about that and the Events Fieldtype was at least for me not of much help, because it's hard to know where to start and what to add where and at what point of time to make everything work together. But once you get how it works it is really brilliant! I hope I can write a blog post about that some day if there's interest in that. So far I'd just want to express my appreciation ?
    1 point
  12. Hi, this module is now in Beta. Still to add full documentation and Facebook App tips. Aiming to complete by the end of the week!
    1 point
  13. I today integrated the multi-language support for all the config fields.
    1 point
  14. Inputfield Selector Select ID Uses the Page List Select inputfield for user-friendly input of page IDs into Inputfield Selector. Overview This module adds a feature to Inputfield Selector, which is most commonly seen in Lister (Find) and Lister Pro. When adding a filter row for "Parent", "Has parent/ancestor" or "ID" the user is expected to enter a page ID to match against. But this is not as user-friendly as it could be because the user may be able to identify the desired page by its title or location in the tree but not know its ID. This is particularly the case for site editors who may not even understand the concept of a page ID. So this module adds a thunderbolt icon to relevant rows in Inputfield Selector. When the icon is clicked a Page List Select inputfield opens in a modal window, allowing the user to visually select a page from the tree. When the modal is closed with "OK" the ID of the selected page is inserted into the filter row. Tip After a page selection has been made in the modal window the "OK" button will automatically receive focus so if you prefer you can close the modal by hitting the Enter key rather than mousing to the OK button. Installation Install the Inputfield Selector Select ID module. https://github.com/Toutouwai/InputfieldSelectorSelectID https://modules.processwire.com/modules/inputfield-selector-select-id/
    1 point
  15. A page autocomplete field would be even more userfriendly. As the selected value you have to get the ID, but the title and ID could be displayed in the input/select. Nice work anyways ?
    1 point
  16. You can try to fine-tune the DB https://dev.mysql.com/doc/refman/5.7/en/fulltext-stopwords.html And for advanced stuff, you can play around with fulltext searches (raw mySQL queries).
    1 point
  17. It would be, but as we all know, life is not as straightforward like that ? There are issues Ryan solves pretty fast after being reported, there are others that take more time and there are some which seem to take forever... and the worst category is in which he is only marginally interested. Also, what we might provide as a "fix" via a PR can easily turn out to be just a workaround and there is no point in submitting such a PR. For example, in all of my use-cases PageTable without an "add new" bottom at the TOP of the table is a UX nightmare, so I have a JS hack to clone the button from the bottom to the top. In my point of view I "fixed" this is issue, but in reality it is just a hack which would be a good fit for this module, I think. Maybe we should call this module PwQuickFixes which might better reflect its intended purpose: temporary workarounds until they get properly fixed. We just need stats to see how many of us is using a particular quick fix, and another way to make our voice heard is to add a kind nudge by asking the user to go to the related Github issue in order to make her/his voice heard too.
    1 point
  18. Thanks a lot to Kongondo and Szabesz for this module. I have a small project on a university website, where they required quite simple task management for their internal research team. They want all actions triggered through emails and SMS because it is not easy to expect the team always log in to their website. I did a quick development based on this module and will share and post it in a new thread.
    1 point
  19. I needed a language switcher so i searched the forum and docs, found very useful stuff, but as im new in processwire (came from joomla) all this is still a bit confusing for me, need time to get use to it i guess. There's probably other people like me get confused in all the power of pw, and need language switcher on the site, so i decided to share what i came up with. Actually its very simple, a lot easier then i thought. There is very nice example in docs using select box (there i found out about $languages array, and its clicked), but you need additional script if you wanna style it, so i came up with something simple: TADAAAAA <?php foreach($languages as $language) : ?> <a href="<?=$page->localUrl($language)?>"><?=$language->title?></a> <?php endforeach;?> Here's another example, but now active language is just a span with active class. (Style used on most websites). <?php foreach($languages as $language) : ?> <?php if($user->language->id == $language->id) :?> <span class="active"><?=$language->title?></span> <?php else : ?> <a href="<?=$page->localUrl($language)?>"><?=$language->title?></a> <?php endif;?> <?php endforeach;?> Here is UIkit dropdown example, same can do with bootstrap, just a bit different markup. <div class="uk-button-dropdown" data-uk-dropdown> <button class="uk-button"><?=$user->language->name?></button> <div class="uk-dropdown uk-dropdown-bottom"> <ul class="uk-nav uk-nav-dropdown"> <?php foreach($languages as $language) : ?> <?php if($user->language->id != $language->id) :?> <li><a href="<?=$page->localUrl($language)?>"><?=$language->title?></a></li> <?php endif;?> <?php endforeach;?> </ul> </div> </div>
    1 point
  20. Just wanted to share the simplest language switcher possible if you only have two languages: <a href="<?= $page->localUrl($languages->findOther()->first()) ?>">DE/EN</a> ??
    1 point
  21. @benbyf To save myself from the headaches, I only use scrapers anymore. No sandboxed accounts, no setup, no invalidated keys every two weeks. instagram-php-scraper has been working great so far. This is all there is to getting recent media of any user id or name: $userid = env('INSTAGRAM_USER_ID'); $instagram = new \InstagramScraper\Instagram(); $account = $instagram->getAccountById($userid); $username = $account->getUsername(); $latestMedia = $instagram->getMedias($username, 10); foreach ($latestMedia as $media) { if ($media->getType() === 'image') { [...] } }
    1 point
  22. I've been using PW for quite a while, now, so I would like to give back to the community that helped me so many times. I had this customer that wanted to use the Google Translate API to automatically translate the site, so I built this function that takes advantage of it without the need to use the API on every page cycle. I put it on a file that gets called on the _init.php, so that I can use it on every template. Here it is: <?php function googleAutoTranslate($page, $field) { // Turn off outputFormatting $page->of(false); // Get current language and field content for this language $current_language = wire('user')->language->name; $field_content = $page->getLanguageValue($current_language, $field); // Is there any content for this language? if($field_content != '') { // Do nothing! } else { // No content, lets translate... // Get default language text $text = $page->getLanguageValue('default', $field); // Translate only if there's content in the default language if($text != '') { // Translate it $apiKey = 'YOUR API KEY HERE'; $default_language = 'pt'; // Your default language here! $url = 'https://www.googleapis.com/language/translate/v2?key=' . $apiKey .'&q=' . rawurlencode($text) . '&source=' . $default_language . '&target=' . $current_language; $json = json_decode(file_get_contents($url)); $field_content = $json->data->translations[0]->translatedText; // Save translated text $page->$field->setLanguageValue($current_language, $field_content); $page->save(); } } // Turn on outputFormatting $page->of(true); // Return result return $field_content; } ?> Whenever you use a field on a template that should be auto translated, just call the function with a page object and the field name, like so: echo googleAutoTranslate($page, 'body'); Features: Translation occurs only once per field, so you don't need to keep paying translations (it stores the translation into the field language); You can correct the translation in the admin area and it won't be overwritten; If you need the translation to be made again, just delete the field content in the needed language. For the translation to occur, content must exist in the default language. I had to fight a little to get this working, so I hope this helps anyone, who comes across this particular need. Nice Things To Have If someone wants to give it a shot to make this into a module, please do. It would be nice to have a checkbox "Enable Google auto translate for this field", when you edit a field input features. Don't Spend Too Much Mind you that the Google translate is a payed service! and needs a Credit Card to get it going (even with $300 free credit); With a relatively small site (and the tests made to get this to work) I already spent about 80.000 translated characters = $3, Hope this helps someone!
    1 point
  23. A bootstrap 4 alpha version exemple with navbar and dropdown : <nav class="navbar navbar-dark bg-primary bg-faded"> <button class="navbar-toggler hidden-sm-up" type="button" data-toggle="collapse" data-target="#exCollapsingNavbar2"> ☰ </button> <div class="collapse navbar-toggleable-xs" id="exCollapsingNavbar2"> <a class="navbar-brand" href="#">Responsive navbar</a> <ul class="nav navbar-nav"> <li class="nav-item active"> <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a> </li> <li class="nav-item dropdown"> <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Languages <span class="caret"></span></a> <ul class="dropdown-menu"> <h6 class="dropdown-header">Dropdown header</h6> <?php foreach($languages as $language) { // determine the "local" URL for this language $url = $page->localUrl($language); // output echo "<li><a class='dropdown-item' href='{$url}'>{$language->title}</a></li>"; } ?> </ul> </li> </ul> </div> </nav>
    1 point
  24. There's is now a translation tool in core that will find all translatable files automatically. Just click and add.
    1 point
×
×
  • Create New...