Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/04/2018 in all areas

  1. This week's version of ProcessWire on the dev branch continues resolution of GitHub issue reports, and it also adds a new text truncation function to our $sanitizer API, something requested from our requests repository: https://processwire.com/blog/posts/processwire-3.0.101-core-updates/ We didn't have a blog post for last week's version 3.0.100—see the core updates section in ProcessWire Weekly #207 for more details on that version.
    10 points
  2. This may come handy ? https://google-webfonts-helper.herokuapp.com/fonts
    3 points
  3. I can totally see why "getting an API key" should be a thing the developers do, but "taking the responsibility for using a 3rd party tool which is likely sending private data to a company in a non EU country" is something clients will have to deal with by the end of the month – especially if you're just a limited-time contractor creating the website for the client to run on their own afterwards.
    2 points
  4. Yeah, since then lots of people have gotten used to it. However: We have an in-house UX rule: Never display an icon without text. So yeah, it can't hurt to put "MENU" below the burger.
    2 points
  5. Have a look here: https://processwire.com/blog/posts/pw-3.0.80/#pro-module-faqs
    2 points
  6. I come from the future and have to tell you ProcessWire is here to stay @gebeer My sync is not connected to git, I am planning to do so, but you know... missing time. I send you the rsync shell script via DM.
    2 points
  7. sure, here are some examples, i have these in a file called schema_helpers.php, which is in my shared functions folder: 1.) function siteSchema() { $page = wire('page'); $schema = array( "@context" => "http://schema.org", "@type" => "Website", "url" => wire('pages')->get(1)->httpUrl, "name" => $page->title, "description" => '', "potentialAction" => array( "@type" => "SearchAction", "target" => wire('pages')->get(1000)->httpUrl . "?q={search_term}", "query-input" => "required name=search_term" ), "about" => array( "@type" => "Thing", "name" => "A very interesting THING", "description" => "Website about a very interesting THING" ) ); if($page->summary) { $schema['description'] = $page->summary; } else { unset($schema['description']); } return '<script type="application/ld+json">' . json_encode($schema) . '</script>'; } 2.) News function jsonldNews($item, $settings) { $image = $item->image ?: getFallbackImage($item); if(!$image) return; $out = ''; $jsonld = array(); $jsonld["@context"] = "http://schema.org/"; $jsonld["@type"] = "NewsArticle"; $jsonld["name"] = $item->title; $jsonld["headline"] = $item->title; $jsonld["url"] = $item->httpUrl; $jsonld["mainEntityOfPage"] = array( '@type' => "WebPage", '@id' => $item->httpUrl ); $jsonld["description"] = $item->summary; $jsonld["datePublished"] = date(DATE_ISO8601, $item->published); $jsonld["dateModified"] = date(DATE_ISO8601, $item->modified); $jsonld["dateline"] = date(DATE_ISO8601, strtotime($item->news_date)); $jsonld["wordCount"] = str_word_count($item->body); $jsonld['author'] = $settings['author']; $jsonld['publisher'] = $settings['entity']; $jsonld['articleBody'] = $item->body; $jsonld['articleSection'] = $item->categories_select->first()->title; // Publisher $pubLogo = wire('pages')->get(3525)->image; if($pubLogo) { $pubLogo = $pubLogo->height(60); $jsonld['publisher'] = array( '@type' =>'Organization', 'name' => 'A Publisher', 'url' => 'https://publisher.org/', 'logo' => array ( '@type' => 'ImageObject', 'url' => $pubLogo->httpUrl, 'height' => $pubLogo->height, 'width' => $pubLogo->width ) ); } // News Items may have a featured image $image = $image->width(696); $jsonld['image'] = array( "@type" => "ImageObject", 'url' => $image->httpUrl, 'height'=> $image->height, 'width' => $image->width ); $out .= '<script type="application/ld+json">' . json_encode($jsonld) . '</script>'; return $out; } 3.) Event function jsonldEvent($event) { if(!$event->event_location_select) return; if($event->template == 'event-child') { // inherit unset fields needed $event->event_link = $event->event_link ? : $event->parent->event_link; $event->body = $event->body ? : $event->parent->body; $event->event_location_select = $event->event_location_select ? : $event->parent->event_location_select; $event->price = $event->price ? : $event->parent->price; $event->currency_code = $event->currency_code ? : $event->parent->currency_code; $event->link = $event->link ? : $event->parent->link; } $out = ''; foreach($event->event_date_m as $ed) { $jsonld = array(); $date8601 = date(DATE_ISO8601, strtotime($ed)); $jsonld["@context"] = "http://schema.org/"; $jsonld["@type"] = "MusicEvent"; $jsonld["name"] = $event->title; $jsonld["url"] = $event->event_link; $jsonld["description"] = $event->body; $jsonld["startDate"] = $date8601; if($event->event_location_select) { $state = $event->event_location_select->state ? $event->event_location_select->state->title : $event->event_location_select->address_state; $jsonld["location"] = array( "@type" => "Place", "name" => $event->event_location_select->title, "url" => $event->event_location_select->link, "address" => array( "@type" => "PostalAddress", "streetAddress" => $event->event_location_select->address_street, "addressLocality" => $event->event_location_select->address_city, "addressRegion" => $state, "postalCode" => $event->event_location_select->address_zip, "addressCountry" => $event->event_location_select->country->title ) ); } if($event->price && $event->currency_code && $event->link) { $jsonld["offers"] = array( "@type" => "Offer", "description" => "Tickets", "price" => $event->price, "priceCurrency" => $event->currency_code, "url" => $event->link ); } $out .= '<script type="application/ld+json">' . json_encode($jsonld) . '</script>'; } return $out; } Also - I don't think you need to use JSON_PRETTY_PRINT
    2 points
  8. On twitter @pwtuts I made this site to: a) help get beginners up and running with PW. b) give something back to a community that has been very helpful (and patient) to me. c) improve my own knowledge because writing about it really drills it home. Modules: AOS - lots of useful admin tools Connect page fields - made tagging and related posts very easy indeed Custom inputfield dependencies - used to hide fields (on child pages) in a multipage post because all blog posts use the same template ProFields: repeater matrix - used for all body content (image, RTE and code fields) Markup Sitemap XML - for submission to google search console ProFields: Auto links - I have a bunch of pre-determined strings in here (that I need to print out and stick on the wall...) Tracy Debugger - still can't use properly IMagick image sizer - very fast compared to GD, especially when some posts have 5+ images and the originals are 2500px wide Tools: NodeJS with the usual suspects: "devDependencies": { "autoprefixer": "^7.1.2", "cssnano": "^3.10.0", "gulp": "^3.9.1", "gulp-postcss": "^7.0.0", "gulp-rename": "^1.2.2", "gulp-sass": "^3.1.0", "gulp-sourcemaps": "^2.6.0", "gulp-uglify": "^3.0.0", "postcss-flexbugs-fixes": "^3.0.0" }, "dependencies": { "bootstrap": "^4.0.0-alpha.6" } Bootstrap 4 (npm) SCSS In short: had a bunch of fun making this, learned loads. and looking forward to updating with more tutorials.
    1 point
  9. I thought I'd start this topic because I seem to be recommending certain courses to people repeatedly, so why not share it with the PW community. The topic can be a review or overview of any IT or non IT-related courses you're doing or have done. I'll start off with a course on teaching you how to learn. https://www.coursera.org/learn/learning-how-to-learn I'm halfway through this course and I can already see huge improvements in the way I'm learning and also my approach to learning. I wished I've taken this course when I was a student! The course can be taken free, and all it takes is a couple of hours of your time. If you have kids that are in school, I think this should be compulsory viewing for all children in academia. If you're into self-improvement or learning, then I can't recommend this course highly enough.
    1 point
  10. Hi Guys, Here's is our most recent website built in collaboration with the Design studio DITHO from Cologne, who designed and coordinated all the process. For now the website is only in German, but there will be a English version soon. https://bedrohte-ordnungen.de/ "Bedrohte Ordnungen" (Threatened Orders) is the display of an ongoing research by the University of Tübingen. Best described on their own words. Here on a hopefully accurate translation Here's a nice showcase video made by DITHO: This is a quite complex website. It's also quite heavy on images, videos and CSS animations, so old computers might struggle a bit to process it. All the website is dynamic and inside PW, including those animations. This is probably the most interesting part of how the website was built, since all the animations were created by DITHO themselves in ProcessWire thanks to a system that I created for them using a repeater field. You can have an idea through these screenshots: The content blocks of each case represent a question each and repeat throughout all the presented cases. Each question has a main content and most have also a hidden block that can be opened by clicking a button. They are created in PW using the very recent FieldGroups https://processwire.com/blog/posts/processwire-3.0.73-and-new-fieldset-types/: The only two third party modules used were AdminOnSteroids by @tpr and the very useful ColorPicker by @Soma. There would be more to talk about, but I don't want to extend myself too much. Hope you guys like it! Just a shout out to DITHO to say again how much fun this collaboration has been
    1 point
  11. Wow, that truncate function will truncate my search for the ultimate truncate function! ? I wonder if the default for the "visible" option should be true rather than false. If my string included entities and markup tags I think in nearly all cases I wouldn't want those invisible items affecting the visible string length.
    1 point
  12. Cue the superman music ..... "Sounds like a job for RockFinder" what do you think @bernhard ?
    1 point
  13. https://mapsplatform.googleblog.com/2018/05/introducing-google-maps-platform.html These are just excerpts from the above link (highlighting by me). This is annoying. Does that really mean, that I have to create an account for every single site I've ever built and used Google Maps, and give Google my credit card details? Forreal? Or - even worse: pester my clients and tell them to create an account for themselves and use their CC? This is terrible business logic, Google.
    1 point
  14. As written on the page I linked in my first post: Just drop @ryan a short message and he will help you.
    1 point
  15. Sad but true. Don't forget: https://www.openstreetmap.org/
    1 point
  16. First: You know what $event->object is because it is an object of the very class you're hooking onto. In the linked docs, the hook is on Pages::saved, so the event object is an instance of Pages (not a PageArray). In your code, you're hooking Page::price, so $event->object is a Page object. If your hook was InputfieldText::firstWord, it would be an InputfieldText instance. Second: I'd avoid passing $event around to other methods. It kills readability so $event should only be used in the hooks themselves, not in further methods or functions. Yes, you can manipulate arguments. The syntax is in the docs section you linked, in your case it would be $event->arguments(2, $unitprice). But that is mostly meant for before hooks where you want to change the behavior of the original, hooked method. It would be better though to pass all necessary arguments to tierprice and addVat one by one instead of manipulating the "magic thing" that is $event, i.e. something like: $unitprice = $this->tierprice($page, $quantity); Best practice to keep code readable is to use a pattern with a public hook method that decorates your hooked class and a couple of private methods which do the work. <?php /* The usual module stuff... */ public function init() { $this->addHook("Page::price", $this, "hookPrice"); } public function hookPrice(HookEvent $event) { $page = $event->object; $quantity = $event->arguments(0); $vat = $event->arguments(1) ?? false; $unitprice = $this->tierprice($page, $quantity); if($vat) $unitprice = $this->addVat($unitprice); $event->return = true; } private function tierprice($page, $quantity) { /* do whatever calculations and return the result */ } /* ... */
    1 point
  17. Yeah, it's just that... non-techy persons are scared when you even mention tech lingo like "API key". They expect that we as developers handle all this stuff and don't bother them with it. I'm off to go reading some leaflet.js and Mapbox tutorials...
    1 point
  18. The last time someone said "The hamburger menu doesn’t work" we tested onpage CTR and... almost no difference at all. It's by far not the best solution but people know it for a long time now. They see it regularly and can handle it. The article was first written in 2015 (according to the WP image path) and therefore things have changed since then. Remember all the "people don't read online!" or "people don't scoll!" statements.
    1 point
  19. I don't really agree with the article. Perhaps that was true back then but nowadays people are used to it (or perhaps I'm too much of a designer :)). According to that logic the eg. the search icon (magnifying glass) could be on a ban list.
    1 point
  20. The cookie contains: domain and path Although both PW instances create the same named cookie. I'd move sites to subdomains. That works without any problems.
    1 point
  21. Hey @Mikel, seams like with the original mailchimp subscribe forms, it is possible (and in my opinion it should be) to resubscribe. I will have a look on that! Thanks for the input. Meanwhile (e.g. for testing) you can use the delete method to completely delete and resubscribe a user. That is working for me with the current version.
    1 point
  22. Houra !!! I don't know why, but in the MaintenanceMode module from @Pete, I get a buggy value. I set the field "Redirect to another URL" to "/waiting.html". The maintenance mode was disable but I have strange value in the filed "Redirect to another page instead of the login page?" : it was set to "Login" and impossible to change it. I just uninstalled and install again the module and now all is OK ! Thanks a lot for your help @dragan, @Robin S and @horst
    1 point
  23. @Mikel Pretty sure you can’t subscribe to a list you previously unsubscribed from. It’s a Mailchimp “feature”.
    1 point
  24. Glad I'm using the e-mail as login and not the username. ? UX Planet - Requiring a user name to login: https://uxplanet.org/7-inexcusable-yet-common-ux-gaffes-that-make-you-look-like-a-total-amateur-cb504a74b917#3b00
    1 point
  25. Wildcard certificates are only for one "complete" domainname like "*.domainname.ext" You need a certificate for every domainname - including subdomains (or you have a wildcard certificate... )
    1 point
  26. The free, cheap and less expensive certificates will cover only one domain - maybe sub-domains, too. There might be "wildcard" certificates that cover every single domain you own but those are either expensive or domains have to defined before. If your hosting company provides Let's encrypt you should go with a certificate for each of your domains. Depending on your overall requirements and project you might want to consider paid certificates.
    1 point
  27. I also use something like @horst but only with without eot, svg and ttf (plus with a stylus or scss mixin), see https://stackoverflow.com/questions/36105194/are-eot-ttf-and-svg-still-necessary-in-the-font-face-declaration
    1 point
  28. In ProcessWire itself I've never used custom fonts. For projects I do it the exact same way as @horst does. As I use .less for CSS I create a _fonts.less import with everything I need. One exception is Typekit. That always gets included with JS.
    1 point
  29. I ever use absolute urls, because then I can match them from within different located css files. Normally I store all fonts under /site/templates/styles/fonts/.
    1 point
  30. It's just like @kongondo said - you have to save a new page before you can add files or images to it. The directory needed to hold the files/images gets created on the first save - then you can add files/images. So in submit(), do $p->save() before setDummyData()... public function submit() { $input = $this->wire('input'); $page = $this->wire('page'); $session = $this->wire('session'); if ($input->post->submit && $this->canEdit()) { if (($p = $this->savePageBasic()) !== false) { $p->addStatus(Page::statusHidden); $p->save(); $this->setDummyData($p); } $session->redirect($page->path); } } P.S. This... $parent = $this->wire('pages')->get($page->path); $p->parent = $parent; ...could be better optimised as... $p->parent = $page;
    1 point
  31. @PWaddict, I agree with @kongondo. If page A has a single page reference field with page B selected in it then page B must not have a single page reference field with page A selected in it. This only applies to two single page reference fields - if one or both are multiple page reference fields then there is no problem. This isn't an issue with this module specifically, just a limitation of PW. Related GitHub issues: https://github.com/processwire/processwire-issues/issues/152 https://github.com/processwire/processwire-issues/issues/572
    1 point
  32. 1. There's a example in the code itself with email: if($email && (strpos($email->value,'@hotmail') !== FALSE)){ // attach an error to the field // and it will get displayed along the field $email->error("Sorry we don't accept hotmail addresses for now."); } Anything the API provides is possible. I can't go into details as there's too much and don't have any examples ready. 2. Of course an array is possible, input->post is also and array. You just have to make it a WireInputData array. https://github.com/processwire/processwire/blob/341342dc5b1c58012ae7cb26cffe2c57cd915552/wire/core/WireInputData.php 3. "Validation" is per Inputfield and it depends. Some inputfields do some sanitations to make sure an expected format or type of value is given (for example email https://github.com/processwire/processwire/blob/341342dc5b1c58012ae7cb26cffe2c57cd915552/wire/modules/Inputfield/InputfieldEmail.module) but most do nothing at all. You can look at all the Inputfields processInput() method to see what it does. Text and Textarea have some Inputfield settings to strip tags for example. It depends also on what the Form is used for and where you use the data afterwards. It's never an issue to save data to DB ie Pages, it's always about what and where you output the data (website, email, ...).
    1 point
  33. thanks @horst will check it out and update the profile.
    1 point
  34. 1 point
  35. ProcessWire 3.8? I must be using the wrong Github repo. ?
    1 point
  36. FYI, Ryan has pushed a fix for this issue to the dev branch.
    1 point
  37. Hi everyone We've just upgraded the forum software to the latest version. There were a few tweaks that needed to be re-applied to the templates but I think I've got them all. If you do notice anything out of the ordinary, please let me know here. EDIT: The forums may run slower than usual for the next couple of hours as part of the process re-indexes all of the post content.
    1 point
  38. <distraction> Sonderforschungsbereich 923! Gotta love the German language! Sorry, but I just can't help myself. It sounds at the same time so bureaucratical and military, but also beautiful. I've heard many standup-comedians making fun of this simple fact, that in German it's easy (and allowed) to put words together to create a new one. For us, it's natural and normal, but for many other people it's like "what the heck"? </distraction>
    1 point
  39. you can just put a get variable ?register=1 on the request and it will show the registration form..
    1 point
  40. The module looks for a GET parameter register. When this is set to 1, it renders the login form. So what you could do is in the temnplate where you render the login form // set GET parameter register to 1 $input->get->register = 1; // render the form $content = $modules->get('LoginRegister')->execute(); I just tried it and it seems to work.
    1 point
  41. NOTE 2022: Better use URL hooks! https://processwire.com/blog/posts/pw-3.0.173/#introducing-url-path-hooks Hidden option ? // site/ready.php $wire->addHookBefore('Page::render', function($event) { $page = $event->object; if($page->template == ...) include(yourcodefile.php); // or any other condition }); // yourcodefile.php <?php namespace ProcessWire; if(!$this->config->ajax) return; // early exit // any other conditions // return json header('Content-Type: application/json'); die(json_encode($yourdata)); @Guy Incognito you might also be interested in this thread:
    1 point
  42. Congrats on account of your first page going live! I like your responsive layout.
    1 point
  43. $pf = $pages->getPageFinder(); $selector = new Selectors($selector); $query = $pf->find($selector, ['returnVerbose' => true, 'returnQuery' => true]); # Show sql $query->getQuery(); # Modify query $query->where($sql); # Run query $query->execute();
    1 point
  44. I am glad that this project is helping ProcessWire getting more devs on board :). I just want to say that I wouldn't have been able to finish ProcessVue if it wasn't for the amazing ProcessWire community. I believe that the community truly is the biggest selling point for new users (like me). Before trying ProcessWire I used OctoberCMS for a while but when I was stuck I got 0 support from the forums, so...althought the CMS is based on the amazing Laravel framework, I just left! I think that ProcessWire is extremely powerful and flexible and with time will become the tool of choice for frontend developers, the new GraphQL module will also help on this direction. Droves of frontend developers are looking for a CMS like this, they just don't know it exists! The usual keywords they use when looking for a SPAs CMS is "Decoupled CMS" or "Headless CMS", and I believe that that's exactly what ProcessWire is for! Some frontend developers prefer to use NodeJS, but the learning curve is huge if you need it for a non trivial project, and the worst thing of all is that after two weeks ANY js tool you may have used is outdated. See for example how Angular has been replaced with React or Vue, and Gulp with Webpack. That doesn't mean that I am against improvements in this regard, I just feel that it's just too much for us poor frontend devs to cope with! ProcessWire is stable, easy to use and won't change API every week. BTW, after that I migrate ProcessVue to GraphQL I am also planning to add Auth0 login integration with JWT, as I think that login/signup is a common feature in SPAs. I am sure I'll have to annoy @Nurguly Ashyrov and the rest of ProcessWire community for getting it in sync with ProcessWire users, but the result should be quite useful
    1 point
  45. I know this is old, but just a follow up to mention that Tracy Debugger has a few options for achieving similar functionality. Files Editor panel lets you test changes without affecting what other users see. When ready you can push the changes live. Template Path panel lets you choose from a variety of templates with -dev, -test etc suffixes. The User Bar has a "Page Versions" component that lets authorized users choose from alternate templates (this is basically a non-superuser version of the Template Path panel. User Dev Template Options - this lets you set users with certain roles to automatically see the page with a different version of the template file. Anyway, thought some of these might be useful to others who come across this topic.
    1 point
  46. Everybody who has import scripts running as a cronjob, there's this effect that the cronjob is run als guest user. So imported pages via API are created and modified by "guest". This is not nice and can lead to confusion. "What?! How can a guest create this page?" To avoid this and set the current user via API you can do this at the beginning after bootstrapping PW: include_once("./index.php"); /** * Overwrite static user for imports. All created pages will now * have created and modified user set to "importer" PW user. * Otherwise API created pages will have the created user "guest" * ------------------------------------------------------------------------------------- */ $importerUser = wire("users")->get("importer"); if($importerUser->id) wire()->setFuel("user", $importerUser, $lock = true); Only thing is you have to create a new superuser with the name you wish to use for such scripts and replace the name in the script. Now if you run this script no matter from where or with what current user you'll have "importer" as the created and modified user. ----- Note: There's a new way to set system vars like $user via wire(name, value), but this doesn't seem to work in this case in my tests. Cause the user will get overwritten again when creating a page by the current user calling the script. I'm not sure it's a bug or what, so it might be possible in future to use the shorter version of wire()->setFuel(name, value).
    1 point
  47. Excellent - I am not sure the best way to achieve this yet, but if you can make it possible to hook into the selector parser, I would happy to have a go a writing a module that allows for using SQL directly in selectors, or at least using mysql function/operators. Not sure the best option yet. The former could be very powerful, but obviously more complex to integrate without problems. I'll have to start looking through the core and getting an idea how the parser works.
    1 point
  48. Hey Soma, Thanks for both examples - I really appreciate you seeing me through on this one! I decided to go with the dummy array for generating the pager links - it works perfectly! and it easily allows me to use either the direct SQL approach, or the original idea I showed in post #2. What I am now wondering is if it would be at all possible to have PW parse a selector that uses a combination of PW selectors and SQL such that you could write something like: $results = $pages->find("template=x, limit=10, sort={ORDER BY DATE(data) DESC, TIME(data) ASC}"); Not sure on the syntax, but the idea is that if the selector parser comes across something inside curly braces (or some other delimiter), it uses that directly in the final SQL query. Maybe in this example you could even leave out the "ORDER BY " as the sort would be inserting that anyway. Maybe this could get way too complex to deal with, so I won't bring it up again
    1 point
  49. Few things that are "nice to know" when building PW modules: Autoload and non-autoload modules: autoload ones are loaded on every page load. So if you need to hook into core, then you probably need autoload. Non-autoload modules are run only by request: $modules->get("myUberModule")->doSomething() When you need hooks? Well.. common things are "do something when page is saved", "alter the output that is generated", "do something before page is accessed" etc.. Actually there is quite a many hooks and best way to find right hook for you need is to ask for it here. Building modules is pretty similar to working with templates. Nothing "special" there. Few notes though: You cannot directly access the PW API variables like $pages, $session, $input etc.. Those are available at $this->pages or wire('pages'). If you have static method(s) in your modules then you need wire('pages') there - so if you want to play it safe always use that (it works on command line scripts also) Modules can have settings - those are very easy to implement (just look examples from other modules that have settings) Modules are cool. init() is run before page is loaded, so if your autoload module needs to know the current page, that is available at ready() method. Forums is your friend, just ask and someone (probably Soma with his quick editing skills) will surely help.
    1 point
×
×
  • Create New...