Leaderboard
Popular Content
Showing content with the highest reputation on 02/12/2020 in all areas
-
I have found this library quite useful in the past. If you are going to support recurring dates, please take a look at the inputfield interface for recurme (it works quite nicely), but please make sure if you implement momentjs for any part of that process be sure to use the timezone version of it. I also think the ability to output recurring dates using RRULE (https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html) please be sure not to follow the broken format used by Recurme. I would recommend a full read of the recurme support thread as it raises lots of issues which should help you to avoid them in this module ?6 points
-
Hi Bernhard, Being able to enter and display Events (or the like) is such a valuable tool for many websites. I am thrilled you have started this project. I cannot over emphasize @adrian's comment on all fronts. A few things that are very helpful in displaying recurring events is the ability to only display the event once. Ie. if you have a recurring event from March 10-15th. You may not want the event to display 6 times if you are viewing the Event list page on March 10th. The recurme module does do quite a few things right, unfortunately it wasn't quite there. Two features standout: 1. The user interface to create recurring dates which also has the ability to remove select dates. Ie. A range from March 10-15, but you can then exclude any date in the range. This avoids a second (essentially duplicate) event needing to be created. 2. Displaying recurring events can be quite a challenge, especially when there is a long list of dates. Recurme used a calendar display for this, which could really display a lot of recurring dates in a small space. Rather than displaying a long list dates in text format. I will send you a pm with some live examples we have built to date and how we display events. Perhaps this will help highlight some of the challenges you may be facing or how people may use your module. This will be such a great addition to the Processwire ecosystem!5 points
-
That works as well! Main reasons I don't (practically) ever use this approach have already been mentioned here: I'd have to block access on template level (may need to do that on a lot of places), search features and highlight lists etc. all have to be aware of this, and so on and so forth. Potentially having multiple developers work on the site doesn't really help either. At some point you're very likely to show publicly something you didn't intend to. Want to schedule pages? install SchedulePages. Need more scheduled content? Add two fields to the template. Easy as it gets ? Also, as a general rule if thumb, I try to do as little permission/access checking myself as possible. Sure, in this case it's probably not a big deal, but... ? "ProcessWire — there's more than one way to do it" ✌5 points
-
I'm currently building a Fieldtype/Inputfield for selecting date and time ranges (eg for events). There was quite some interest in this thread, so I thought I start a dedicated discussion... Background: I guess everybody of us knows the problem: You want to present events on your website and you start with a new template and a title and body field... For events you'll also need a date, so you add a datetime field called "eventdate". Maybe the event does not take place on a specific day but on multiple days, so you need a second field... Ok, you rename the first field to "date_from" and add a second field called "date_to". So far, so good. Then you want to list your events on the frontend. Simple thanks to the pw API, you might think. But you realize that it's not THAT simple... Which events take place on a specific day? What would the selector be? Yeah, it's not that complicated... it would be something like: $from = strtotime("2020-01-01"); $to = strtotime("2020-02-01"); $events = $pages->find("template=event, date_from<$to, date_to>$from"); Why? See this example, where the first vertical line represents the $to variable and the second is $from: The start of the event must be left of $to and the end must be right of $from ? Ok, not that complicated... but wait... what if the date range of the event (or whatever) was not from 2020-01-18 to 2020-02-25 but from 18 TO 25 (backwards)? The selector would be wrong in that case. And did you realize the wrong operator in the selector? We used date_to>$from, which would mean that an event starting on 2020-01-01 would NOT be found! The correct selector would be >=$from. That's just an example of how many little problems can arise in those szenarios and you quickly realize that the more you get into it, the more complicated it gets... Next, you might want to have full day events. What to do? Adding a checkbox for that could be a solution, but at the latest now the problems really begin: If the checkbox is checked, the user should not input times, but only dates! That's not possible with the internal datetime field - or at least you would have to do quite some javascript coding. So you add 2 other fields: time_from and time_to. You configure your date fields to only hold the date portion of the timestamp and show the time inputfields only if the "fullday" checkbox is not checked. We now have 5 fields to handle a seemingly simple task of storing an event date. That's not only taking up a lot of space in the page editor, you'll also have to refactor all your selectors that you might already have had in place until now! Idea So the idea of this module is to make all that tedious task of adding fields, thinking about the correct selectors etc. obsolete and have one single field that takes care of it and makes it easy to query for events in a given timeframe. The GUI is Google-Calendar inspired (I'm acutally right now liking the detail that the second time input comes in front of the date input). I went ahead and just adopted that: Next steps I'm now starting to build the FINDING part of the module and I'm not sure what is the best way yet. Options I'm thinking of are: // timestamps $from = strtotime("2020-01-01"); $to = strtotime("2020-02-01")+1; // last second of january // option 1 $pages->find("template=event, eventdate.isInRange=$from|$to"); $pages->find("template=event, eventdate.isOnDay=$from"); $pages->find("template=event, eventdate.isInMonth=$from"); $pages->find("template=event, eventdate.isInYear=$from"); // option 2 $finder = $modules->get("RockDaterangeFinder"); $finder->findInRange("eventdate", $from, $to, "template=event"); $finder->findOnDay("eventdate", $from, "template=event"); ... I think option 1 is cleaner and easier to use and develop, so I'll continue with this option ? Future As @gebeer already asked here 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. 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. Nevertheless 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 (or the abandoned recurme field). For recurring events the finding process would be a lot more complicated though, so there it might be better to use an approach similar to option 2 in the example above.4 points
-
Hi @teppo that's a very good point and a reminder, that adding rrule support might be overkill for this module. Maybe it would make more sense to have this in a separate module! Just implemented a little funktion that can list items before and after a given date: The nice thing is that you can specify multiple templates. The idea is to show events in the footer and there it might make sense to show also events of the near past ? Past events are sorted by end date, future events are sorted by start date. Quite nice and quite easy to query: Not sure where to put this though. Right now it's a hook in ready.php - but there it is not reusable. I thought of adding this to every RockDaterange object, but it feels wrong. Maybe adding a helper module for such features would make sense? Actually the wording of this method should be findBeforeAndAfter instead of GET... I'll change that!4 points
-
Just my five cents: this project seems like something that would be very useful without any support for recurring. I'd love to get my hands on this feature, and I'm pretty sure I'll never even need that latter part. In fact more commonly I've needed reoccurring events (hope that makes sense; basically I mean events with multiple, manually specified dates rather than a set of rules to govern when and how often they should recur). Recurring rules can get extremely complicated: "this event occurs every Friday between January and August except specific days x, y, and z — and then it also occurs on this particular Wednesday and that Tuesday there, but on those days there needs to be this additional note on the content". Done that a few times, but I try my best to steer away from those implementations. It's very rarely worth the hassle. In my experience lot of that mess can be circumvented by allowing multiple dates (or date ranges) for one event ?4 points
-
@daiquiri - with respect, i think you're missing a larger point about this system. Basically what you are trying to do doesn't make any sense, and you can't compare to WordPress because WP is a bucket structured system whereas PW is a hierarchical tree system. The homepage represents the root of your site (/). That is basically a sacred thing here - it should not be changed, and it should not need to be changed so i think you should re-assess why you need/want to do this and come up with a different way or reconfigure your thinking about how to achieve what you want. and in all of the years of working and developing in this, i have never heard of anyone needing or wanting to clone the homepage. The easy way to do it is: Current Home Page with old template (home.php) New Homepage (subhome.php) move all public content branches below this new branch Some subpage Some other subpage Hundreds of other sub and sub sub sub pages with lots of content, which I don't want to manually move around/clone etc then just reconfigure your code in home.php and subhome.php (e.g. create a new home.php and rename home.php to subhome.php)3 points
-
I just released the beta version on github. Updated my first post with the download URL. A new video is coming soon, as many features have changed. For example panels are only being used for a module's settings. All other actions are executed via AJAX and show a notification on success. Happy testing, and have fun with it.3 points
-
I've added a hooks folder where all daterange hooks can be put into: All hooks can be disabled in the module config: Not sure if that makes sense at all, but it was fun to build ?3 points
-
This is a good point! In one case we needed a set of "real-time" statistics displayed on all pages of a site. Though the site was internal, it was relatively heavy on traffic (lots of users reloading it all the time), and users very much depended on it being fast, as it was an integral part of their workflow. The solution we came up with was a simple cron script that pulled the data from a separate database, wrote it to a text document on the disk, and then (an equally simple) JS script that polled that text file and injected the content on the page. Technically the solution had nothing to do with ProcessWire — just that the result was injected (via JS) within otherwise "static" content ? Actually... you can always embed Vue apps within a ProcessWire generated page. In my experience Vue is pretty great for that sort of stuff in fact. But of course you don't have to do that here, and the jQuery / vanilla JS route is pretty much guaranteed to be much simpler ?3 points
-
For 90% of these kinds of cases I do it like @Jens Martsch - dotnetic suggested, and in the template of the page (event, news item, etc) I have: // Throw 404 if item is future-dated if(!$user->isLoggedin() && $page->getUnformatted('date_1') > time()) throw new Wire404Exception(); But on a complex site where the pages might be queried from many selectors in many different places then unpublishing is the way to go.3 points
-
Other handy selectors added ? Any other ideas that could be necessary or helpful? It's really easy to add others ? // returns all pages with a date in a specified year case 'inYear': // split value by semicolon $str = $this->getFromToStrings($value, 'year'); $query->where("{$table}.data<='{$str->to}'"); $query->where("{$table}.end>='{$str->from}'"); break; // returns all pages that start before a given date case 'startsBefore': // split value by semicolon $str = $this->getDatestring($value); $query->where("{$table}.data<'$str'"); break; Current options: inRange onDay inMonth inYear startsBefore endsBefore startsAfter endsAfter3 points
-
Suppose you have an images field and you want editors to upload a specific number of images to that field. Using a hook in /site/ready.php you can display a field error in Page Edit if the number of images in the field does not match the required number. Just like the standard "required" behaviour, the requirement does not prevent the field being saved if the number of images is not correct so you would still want to check the image count in your template. $wire->addHookAfter('InputfieldImage::processInput', function(HookEvent $event) { $inputfield = $event->object; // Only for this field if($inputfield->hasField != 'images') return; // Only in ProcessPageEdit if($this->process != 'ProcessPageEdit') return; $page = $this->process->getPage(); // Only for this template if($page->template == 'home') { if(count($inputfield->value) !== 4) $inputfield->error("Please upload exactly 4 images to this field"); } });2 points
-
$(document).on('repeateradd', function() { alert('added'); }); https://github.com/processwire/processwire/blob/master/wire/modules/Fieldtype/FieldtypeRepeater/InputfieldRepeater.js#L3302 points
-
You can't, without running into major headaches, change the root page (i.e. "Home"). What you can do is create a copy and move all children with the exception of the system fields (admin, trash, 404) under the new home. Then you can adapt the Home page to your liking (i.e. switch template, edit contents, whatever). Here's a small script that automates that task. This hasn't been tested extensively, so I don't advise to run this on a production system, only on a copy (or at the very least make a test run on a copy and then make sure you have a full, working database backup at hand). You can copy this code into a script (e.g. as "clonehome.php") in your PW installation root and run it from the command line. <?php namespace ProcessWire; if(PHP_SAPI != 'cli') exit; include('index.php'); error_reporting(E_ALL); ini_set("display_errors", true); /* ************************************************************** * CONFIGURATION FOR CLONING * *************************************************************/ $adminUser = "admin"; // PW Backend User $childrenToLeave = [ $config->adminRootPageID, $config->trashPageID, $config->http404PageID = 27 ]; /* ************************************************************** * END OF CONFIGURATION * *************************************************************/ $session->forceLogin($users->get($adminUser)); $home = $pages->get($config->rootPageID); echo "Cloning Home" . PHP_EOL; $newOldHome = clone $home; $newOldHome->setQuietly('_cloning', $home); $newOldHome->addStatus(Page::statusSystemOverride); $newOldHome->removeStatus(Page::statusSystem); $newOldHome->removeStatus(Page::statusSystemID); $newOldHome->id = 0; $newOldHome->setIsNew(true); $newOldHome->parent_id = $home->id; $newOldHome->of(false); $newOldHome->set('numChildren', 0); $newOldHome->removeStatus(Page::statusSystemOverride); $pages->save($newOldHome, ["quiet" => true]); echo "Home page cloned, new id is {$newOldHome->id}." . PHP_EOL; $childrenToLeave[] = $newOldHome->id; echo "Moving children:" . PHP_EOL; // Now move all children, with the exclusion of admin tree and special pages (404, Trash) // as configured in $childrenToLeave foreach($pages->find("parent=$home, include=all") as $child) { if(in_array($child->id, $childrenToLeave)) continue; echo "- {$child->name}..."; $child->of(true); $child->parent = $newOldHome; $child->save(); $child->of(true); echo "[X] Done" . PHP_EOL; } echo "FINISHED. All children moved." . PHP_EOL;2 points
-
So you need "secured-files-dir" directory on the same level as your site root: - www -- your-site-root -- secured-files-dir2 points
-
U need absolute/relative filepath but not url. Ex: /var/www/secure/ or c:\www\secure or something like ./../secure if U use windows local server and linux production server2 points
-
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. 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. That sure is a long read but well worth it.2 points
-
Hey @bernhard - those are now the defaults (as per the Tracy core defaults). They are also configurable in the module settings: and you can also override them for a specific dump with: d($obj, 'title', ['collapse' => 1, 'collapse_count' => 1]); which might be handy if you are dumping lots of the same object/array in a loop and you don't want them all open which not only takes up more physical space, but also more reources.2 points
-
Even though not officialy supported by PW3 I've used this module in the past successfully: https://processwire.com/talk/topic/711-release-schedulepages/2 points
-
Hi @saschapi! I'm not aware of a module that enables this along with lazyCron but you could try placing something like this under site/ready.php $wire->addHook('LazyCron::everyDay', function($e){ $posts = $this->pages->find('status=unpublished, template=post'); foreach($posts as $post){ if($post->schedule_publish_date <= time()){ $post->of(false); $post->status([]); $post->save(); } } }); The page template you want to publish, would have a schedule_publish_date field, where you can set a publish date and time.2 points
-
I worked hard on the module the last days, and rewrote much of the core logic and added some more features. I wanted to record a screencast yesterday, but my recording software ignored my mic. So I show you some annotated screenshots instead. Since then, many things changed again. Right now I am working on downloading and installing a module via a URL, and also making a transition to modal dialogs instead of panels, if applicable. I moved the whole button logic from the PHP script to a vue component. So I am flexible how to display the buttons, and I can reuse them in the cards and in the table layout: I added a reduced card layout, which moves the description of a module into the "more information" accordion: Updated TODOs with much more features to come. I will work on the module in the next 2 days and hope to make so much progress, that I can finally release the first version on github.2 points
-
@daiquiri, the homepage is sacred in the sense that it represents the root of the site (/) and all pages must descend from this root page, this is fundamental to the structure of the internet, domains and such. PW was deliberately designed this way from the inception, as it mirrors the "reality" of the internet - the descendant tree structure of a website's pages off the root. Your content configuration may not be sustainable if you find yourself having to go through the effort you are describing. But if you know the API, you can easily change pages of any type of template to a new parent with 1-2 lines of api code.1 point
-
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. That sounds good, thx ? Yeah. There are some complicated things involved when displaying events... What if the user visited the List on March 14th? And how to do proper limit and pagination queries? Eg find exactly 12 events but show recurring only once... Not sure how one would solve that properly ? Thx everybody for the feedback. I'll read the recurme thread that I followed only loosely and finish my current project with the basic implementation of RockDaterange (without RRULE). We'll see how that goes and what might be added in the future...1 point
-
Thanks Arjen, i was about to write something about the process today. Much appreciated all the help. Hannie1 point
-
Coolio, no rush. I think this might have also been to do with having html entity encoders set on those ckeditor fields. Have no idea why I did that, maybe I did it testing something else.1 point
-
1 point
-
Sorry for the spam, but found a solution. I am not an expert on prepping strings for the database, but replace the line here with the below to make it unicode aware fixes things for me: $processed_index = preg_replace('/\s+/u', ' ', $processed_index);1 point
-
@uncle_bobson Another way to achieve more or less the same thing, is to use PW's markup cache. Perhaps not suitable if you have intervals of just seconds, but for other use-cases. Of course, that approach won't help if you expect the data to update without page-refresh. But maybe helpful if you have a lot of traffic, and want to reduce "behind-the-scenes" queries.1 point
-
@teppoThanks for the feedback. I'll just do periodic polling. Its fine. If I need quicker updates, without spamming so much, I'll just use the "long polling" hack, or signalR. I see now that there would be no problem using signalR with processwire. My confusion was really about howto use vuejs with processwire. As both of them generate the html code for a page, they would be stepping on each other toes. I somehow thought i absolutely needed vuejs, if i was going to do any dynamic changes in the DOM. But I can generate the page with processwire, and then just use jQuery to do the dynamic updates to the DOM.1 point
-
Meanwhile most stuff has been fixed and we're going to clean up and upgrade ProcessWire with proper multilingual set-up in one installation.1 point
-
To be fair publishing (or un-publishing) pages at set time vs. just listing pages based on a datetime field are two different use cases. In some cases the distinction may not matter, but in others it will — i.e. when something really shouldn't be viewable before a predefined date/time ?1 point
-
@nabo What's your use-case? From a security point of view it's not a good idea to allow everything. Surely you have an idea what kind of file-types will be used? I found another forum thread where basically the same question was asked, and the gist of it was: No, you can't. Leaving the allowed extension config list empty makes it unusable, and just entering a wildcard * won't work either. @ryan takes security matters very seriously, and personally, I wouldn't want to have such a "everything goes" option built-in the core, too. If you have to, for some reason, import data from another system, and create / populate fields via API (batch actions), you can temporarily allow each file extension that comes your way, and then switch back to a "normal" default set after save. But I guess you were asking about using the GUI options.1 point
-
1 point
-
If I understood this correctly (instead of text, there's now just an icon?) I would actually recommend against this — simply because icons will never be as obvious as text labels. From an usability point of view text labels are much better ? From an accessibility point of view, on the other hand, this is just fine — as long as your checkboxes still have proper labels. If the icons are images an alt text is quite enough, but if they're something else (<i> with FA classes etc.) you should hide them from screen readers with aria-hidden="true" and then introduce a separate screen reader only text version.1 point
-
1 point
-
Little improvements to the input: 1) Checkboxes do now show an icon. I think that's a lot more intuitive! 2) You can input dates and times using the "comma" keyboard key (both regular comma and the numblock comma). This is convenient for german keyboards that have a comma instead of a dot right beside the 0 digit): I also did quite some refactoring and changed the db schema so that the data column holds the timestamp of the first second of the timerange. This makes it possible to choose the range field as sort option in the template settings.1 point
-
I think this already looks quite promising ? $selectors = [ "template=event", "template=event, range.inRange=2020-01-01;2021-01-01", "template=event, range.inRange=2020-01-01;2020-02-01", "template=event, range.inRange=2020-02-01;2020-03-01", "template=event, range.inRange=2020-04-01;2020-05-01", ]; foreach($selectors as $selector) { $out = ''; $nl = ''; foreach($pages->find($selector) as $p) { $out .= $nl.$p->getFormatted('range'); $nl = "\n"; } d($out, $selector); } This now also works with backwards ranges (eg 19.3.2020 to 10.2.2020) because I store a separate START and END timestamp in the database: I've also implemented onDay, inMonth, inYear selectors: $selectors = [ "template=event", "template=event, range.onDay=2020-04-15", "template=event, range.inMonth=2020-03", "template=event, range.inYear=2021", ]; This also works using timestamps: $stamp = strtotime("2020-04-15"); $selectors = [ "template=event", "template=event, range.onDay=$stamp", "template=event, range.inMonth=$stamp", "template=event, range.inYear=$stamp", ]; Even sorting works out of the box - PW is once more impressive ?1 point
-
echo $results->renderPager(array( 'linkMarkup' => "<a href='{url}#YOURANCHOR'><span>{out}</span></a>" ));1 point
-
Thank you horst, this is exactly what I was looking for. For those interested, this is my working module below, which adds in icons based on an select options field. <?php class DynamicIcons extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Dynamic icons for the page tree based on field values', 'version' => 1, 'summary' => 'Module to change the icon on the page tree depending on field values.', 'singular' => true, 'autoload' => true, ); } public function init() { $this->addHookAfter('ProcessPageListRender::getPageLabel', $this, 'addPageListLabelItems'); } public function addPageListLabelItems($event) { $page = $event->arguments('page'); $page->of(false); // Check options field for correct value if($page->content_type == '1') { // Add fontawesomeicon $styleItem = "<i class=\"fa fa-file-text-o\"></i>"; // Add to pagetree $event->return = $styleItem . $event->return; } } } (This just shows one options but obviously you could add in additional icons for different field values)1 point
-
Assuming I understand the need correctly, what I usually do add this to the <head> section of the main markup include: <head> <!-- all your typical <head> stuff --> <?php $file = "styles/$page->template.css"; if(is_file($config->paths->templates . $file)) { echo "<link rel='stylesheet' type='text/css' href='{$config->urls->templates}$file' />"; } $file = "scripts/$page->template.js"; if(is_file($config->paths->templates . $file)) { echo "<script src='{$config->urls->templates}$file'></script>"; } ?> </head> Using this method, if you have a template named 'product', then it could have dedicated CSS and JS files in /site/templates/styles/product.css and /site/templates/scripts/product.js, when you need it. The nice thing about this is that it's just a system rather than hard coded file. If you determine you need something unique for the CSS (or JS) on pages using some template, the you can just create the CSS (or JS) file and have it start working automatically. You can take this further too. For instance, you could use the same technique with page IDs to assign custom CSS/JS files to specific pages.1 point