Leaderboard
Popular Content
Showing content with the highest reputation on 06/02/2014 in all areas
-
I was going to start a new thread labeled "Blown Away", but decided I really should just add a new comment on this thread that I started several weeks ago... My learning and time spent with Processwire has been an "on again - off again" process. I have had some serious "I will never learn this" moments, but I am pleased to say that I am currently thrilled and seduced by the potential that PW offers. "Blown Away" really does describe it. After reading many, many PW forum threads and following some of the tutorials it really is beginning to make sense. I have done some reading on PHP and even ordered a Quick Start book on PHP. This book, more than the websites, has really made me go back to the copy and paste template code that I have been using and figure out what is actually going on. Today I spent a couple of hours slowly rereading (with much greater comprehension) the PW API. I won't go into the details but lately I have been having those "aha" moments. I am also beginning to have fun and even welcome random PW thoughts that float into my brain at odd times. I am sure that many of you can relate to this feeling. I have fiddled with several CMS platforms over the years and know my way around html and css, but I have never felt so enthused about the learning curve ahead. My hats off to the folks that have developed ProcessWire. I also want to thank all the forum members who have offered great help and suggestions along this journey...10 points
-
Sorry to waste everyone's time. I figured it out after much panic. In my tests I had left include=all out of the selector for the repeater. Without that it was returning results while logged in as a superuser but not when using it as a guest. I finally clued in, added it and suddenly my life is rosy(er) again. Thanks to Craig, CStevens and Teppo for responding to my goofy panic.4 points
-
Setting ->of(), and the image field will always be an array, no matter what the maxFiles is set to. ( was maybe better if Ryan wasn't that nice for the single image and it would always be an array )3 points
-
Continuing from my previous post in this thread about some selector enhancements available on the dev branch, we've got a couple more advanced options for use in selectors in case anyone is interested: OR-groups These let you specify multiple expressions and only one of them has to match in order for the selector to match. It's a way of saying "either this has to match OR that has to match". This is useful because selectors always assumed AND – meaning everything has to match. While you have always been able to use the pipe "|" to specify ORs for fields or values or both, the scope of it was just that field=value statement only. Now we have something new called OR-groups. These let you create multiple selector groups and only one of them has to match. You can specify OR-groups by surrounding selectors in parenthesis. An example demonstrates it best. Lets say that we wanted to find all "product" pages that were in stock, and either in a featured date range, or had a highlighted checkbox checked. Previously we would do like this with two separate find operations: $items = $pages->find("template=product, stock>0, featured_from<=today, featured_to>=today"); $items->add($pages->find("template=product, stock>0, highlighted=1")); Now we can do it in one find operation: $items = $pages->find("template=product, stock>0, (featured_from<=today, featured_to>=today), (highlighted=1)"); Above are two selectors surrounded in parenthesis. Only one of them has to match. You can specify as many of them as you want. This type of OR expression is something you couldn't previously do with selectors. Think of the parenthesis as a way of saying "this is optional". But of course, at least one of your parenthesized selectors has to match in order for the full selector to match. I'm guessing the above usage probably covers 99% of the situations where you might need it. But lets say that you want to have different combinations of OR expressions. You can create named groups that OR with each-other by specifying: foo=(selector1), bar=(selector2), foo=(selector3), bar=(selector4) In the above you'd replace "foo" and "bar" with names of your choice. And you'd replace the "selector" with any selector strings. Those foo/bar names aren't referring to fields, instead they are just named groups that you can name however you want. In that selector, at least one of the "foo" named selectors would have to match, and at least one of the "bar" named selectors would have to match. If you didn't use the foo/bar named groups here (but still used the parenthesis), then only one of the 4 selectors would be required to match. Sub-selectors Some of you are already familiar with these because it was committed to the dev branch a couple weeks ago (and I think may have been outlined elsewhere in the forums). Sub-selectors let you put a selector within a selector, enabling you to perform more complex matches that used to require you to use separate API calls. These can be used on the 'id' property of any field that maps to a page. The 'id' property is assumed when referring to a page reference or a parent, so it's not necessary to specify it unless you want to, i.e. "field" and "field.id" mean the same thing in this case. Sub-selectors are specified between [square brackets]. For example, lets say we are matching products and our product template has a "company" page field. Each company also has it's own page field where all the company locations are identified. Lets say we want to find all products that are made by a company that has more than 5 locations and at least one of those locations has "Finland" in the title. Previously we would have had to do it like this: $companies = $pages->find("template=company, locations>5, locations.title%=Finland"); $items = $pages->find("template=product, company=$companies"); That's easy enough. But now it's even simpler, as you can do it in one operation: $items = $pages->find("template=product, company=[locations>5, locations.title%=Finland]"); When you've got a "field=[value]" selector, any properties you refer to in "[value]" assume the "field", so "locations" above is referring to a property of the "company" field.3 points
-
Currency Conversion for ProcessWire This module is designed for performing currency conversions among ~165 world currencies. It uses OpenExchangeRates.org (or compatible) for data so that currency exchange rates are always up-to-date. It provides various API functions that you can use to convert from one currency to another. This is especially handy for generating rate tables in multiple currencies or giving users of your site the option to see prices in their currency. How to install How to use API documentation Modules directory page GitHub Page Download ZIP Live Example Requires ProcessWire 2.4.0 or newer. To use the quick-installer from your modules screen, paste in ServiceCurrencyConversion. Basic Example $cc = $modules->get('ServiceCurrencyConversion'); $dollars = 100; // amount of currency we want to convert $euros = $cc->convert('USD', 'EUR', $dollars); echo "<p>$dollars US Dollars equals $euros Euros</p>"; For a live example of a currency conversion tool built with this module see the included convert.php file and test it out here.2 points
-
Textarea Markup inputfield Loosely based on core module InputfieldMarkup, InputfieldTextareaMarkup works with textareas (FieldtypeTextarea) and outputs plain text, markup and optionally values from other fields in Page Edit (backend). That output can be configured via field settings (Input tab) and then modified on a per-page basis, though only by superusers. For an example this: Hello World, I'm a {{template}}, my ID is {{id}} and my name is {{name}}! Would result in a non-editable (except by superusers) "markup field" with content along these lines: Hello World, I'm a basic-page, my ID is 1001 and my name is About! Content pulled from other fields is sanitised using $sanitizer->text() with default options, so no markup should get through, max length for individual field value is 255 etc. The module is available from GitHub. For more details check out README and/or modules directory page.2 points
-
100 fields is no problem. It seems though like a project that would gain great benefit from ProFields.2 points
-
I'm finally continuing this module - thanks to Ole who's sponsoring it. Please post all open bugs here or directly at GitHub so I get an overview on what to do (you don't need to repost them if they are already posted here of course). Thanks, nico2 points
-
2 points
-
Ok, thanks for the explanation - it all makes sense now I don't know what your getTpl() method actually does, but this will also return the template file's full path: echo $page->template->filename; Maybe you are already using this as part of getTpl()?2 points
-
You would use a after Page::deleteReady hook to fetch the page that's going to be deleted. This hook is called when page is deletable and actually WILL get deleted right after. $this->addHook("Class:method", $this, "someMethod"); is to add a new method to a class with a hook. You would give it addHookAfter or addHookBefore.2 points
-
I am sure some of you must have noticed my stumbling around in the dark while getting used to the ProcessWire system. Someday I hope to emerge as a user who brings more to the table than just silly newbie questions. I am sitting down with a mug of really good coffee so I thought I would offer my feelings and reactions to ProcessWire thus far… Quick background: I am a photographer with a long history in photojournalism and commercial work. I have also enjoyed doing web work for years. I built quite a few static sites before searching for a CMS system that felt like home. I must have tested about a dozen or so before spending some real time with Wordpress and then MODx. I liked Wordpress but the template system was awkward for me to me customize. I then found MODx Evo. I stuck with Evo for years and found it very designer friendly. I am not a code developer at all but Evo allowed me the flexibility to design static test pages using clean HTML and then create my Evo template from that foundation. MODx uses a system of combining placeholder code using Chunks, programmed Snippets and Template Variables (TVs) for dynamic forks in the road. Forgive me: I have never been well versed in web tech jargon. One of the features (or liabilities) with MODx is that it uses its own template language. When you deploy a Snippet you need a Snippet “Call” to set parameters on how the Snippet will function. Usually you would need a special template for the Snippet as well. This process is not totally intuitive and has its own learning curve. Then along came the entirely new branch of MODx called Revolution, or Revo for short. Revo was more powerful but also more complex. The nice thing with Revo is that you could spend more time away from the root folder or using an FTP client to upload and install Snippets. The Package Management system is a powerful means of installing and updating the various Snippets and plugins. Updating these building blocks in Evo is more of a pain; manual copy and paste effort required. What I did not like with Revo is that much of the placeholder and template syntax changed from Evo. The changes were subtle but deadly if you confused the two. The main issue I have with Revo is how slow the Manager (admin) system is. The amount of stuff (very techie term here) in Revo is overwhelming. Some of my clients who used the Revo Manager sporadically would always forget how to do things. To be honest I would have the same issue on occasion. With MODx we had Evo, then Revo, then the whole cloud system and now MODx III. It sort of gets confusing. To counter this the forum now has a zillion sections that cater to all the MODx project branches. But I find doing a search on my issues or questions revealed some confusing links to information that focuses on a different branch or is outdated to the system I am working with. I guess this last year was a difficult year for MODx: growing pains and money, etc. The whole technology of Revo, the Cloud and the loss of some of its main core programmers (Shaun McCormick) has created some signal-to-noise-ratio issues. Last year was a terrible year for me personally as well. The joy of buying a new project house was crushed by the death of my father and my only sibling (in South Africa) in the space of just four months. Coming out of this fog I sought of stumbled on some interesting chatter about MODx users switching to ProcessWire. The rest of this quick moving journey has been interesting to say the least. My reaction to PW has been filled with both initial confusion and admiration. I thought my not knowing any PhP was going to be a deal breaker. I sort of had initial writer’s block with the blank page. The PW installation would go well, but then what? But after playing around with several local test installs I can see how liberating and powerful the PW API, the template system and Fields really are. I am slowly picking up some basic use of PhP statements. Doing so is more valuable and efficient than the MODx learning curve with it’s proprietary template syntax. I suspect my working knowledge of the PhP that will make using PW easier will only grow with time. That is my hope for sure. The thing I like about the PW Admin is the speed and the whole weight of the backend. Compare the jQuery Admin to the heavy, heavy MODx Revo Manager and there is no contest. It works better on the iPad as well. My clients have commented on how much “stuff” there is in the Revo Manager. I can’t wait to show them how fast and simple the PW Admin is by comparison. One of my issues is letting MODx go. The community has been great. I cant tell you all how much I admire and appreciate folks like Susan Ottwell, Bob Ray, Jay Gilmore and countless others. Susan has over 20,000 posts on the MODx forum. Just about all of them are consistently helpful and insightful. Being a heavy forum contributor can lead to one’s becoming impatient and suffering from burnout, but Susan’s helpful attitude has been amazing. But my heart tells me that I am better suited to learning ProcessWire rather than the awkward mix of MODx Evo and Revo that I have been using to this point. I think I am also trying to duplicate some MODx procedures when I work with my PW test projects. I think that time will be on my side as I become more comfortable doing things the “ProcessWire way”. Anyway, I am not sure where I am going with this, I just wanted to offer my $.02 and to say how grateful I am with all of you who have shown patience with my initial learning. Cheers, Max2 points
-
It's a pitty but web-development is not always about the best route. Time is limiting factor in the most development processes. And supporting unsupported browser features can have a negative effect on the behaviour on the up-to-date browsers. You've to weight your markup/design decisions carefully. The rule, stated by Owzim is logical & easy to understand for both the customer & development organisation. This is a handhold for de 'average' website you build. And if the customer needs a bigger backward compatibility, the boundary is clear. So they know it's more work and they know the bill will be bigger. To make a rule for backwards compatibility is a pretty good thing. Where you put boundary it's up to you, but it should be clear for both customer and developer.2 points
-
2 points
-
wha is. getTpl() ? mabe u need .provision full path ? wire( 'config' )->paths->templates2 points
-
@zyON: at that point the original name, one without "pageid_" prefix, is nowhere to be found. Hence you actually need to strip the prefix to get the original name. Take a look at how ProcessWire itself does this when restoring pages from trash: https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/Pages.php#L1006.2 points
-
I've done a quick search through the forums and found a couple of similar threads to this, but none of them seemed to work in quite the way I'm looking for (or maybe they did and they just went over my head) so I thought I'd start a new thread for it. What I would like to be able to do is create new pages (projects) on my site but with the ability to mark them as private so that only someone with a password (set in the back end) can view that particular page. I'm not sure if this is best approached with templates, roles or some combination of both. It may be that there is only ever one private project, or it may run into maybe 10-12, each with their own individual password set when the project is created. What I have so far is a project template file that I use for all the artwork pages and a modified version with the addition of a password field. Any help is much appreciated.1 point
-
I'm guessing "tags" here is something you'd need to be testing for. $randomimg = $randogal->images->find("tags=fave")->first(); Haven't actually used them recently so not 100% sure.1 point
-
I've figured out a way to have this work in both scenarios, though still a bit hackish.. https://gist.github.com/outflux3/0a013ea20b46e706a6f9 say you have pages being managed by PageTable, and they all live somewhere other than children of the page managing the pageTable items, and you want to be able to have a visible page reference field on the PageTable items; when editing the item from somewhere other than the PageTable, the module first checks to see if it is already in the PageTable array and if not, it adds it (using the page reference).. when you add it from the page managing the items, i have the users leave out the page reference and then when saving the page, it sets all of the items that don't have the page reference, to the page where they are now associated with.. hope i'm making sense...1 point
-
It is possible to extend the images field with extra fields: https://processwire.com/talk/topic/417-extending-image-field/?p=3351 but the simplest option for you might be to enable tags and write "fav" or something like that in there. Details tab > Use Tags? Or you could also have one image per page and then you have complete flexibility in adding custom fields for each image.1 point
-
@vxda: I think you cannot do on the template. You need to do it with a module. Please refer to the API of that and to the "Hello World" module. If you have any questions than, maybe what hook to use, please ask here, (for any further help). Also you need not to include an external mailer. You can use the new wiremail() function and one of the new wireMail-extension modules: teppos SwiftMailer or my WireMailSmtp.1 point
-
Ok, I just committed another update and I just tested myself with some cyrillic characters and I think everything should be working fine now. I also fixed the blank dropdown issue. Now if there are no edit modes set in the config, the editor is not available at all from the Children tab. Please let me know how it goes for you.1 point
-
This module accomplishes exactly what I was looking for today. Thank you very much Adrian for making this available.1 point
-
Ivan, I am really not very experienced with non-latin characters, but I just changed page name sanitizer to include: "Sanitizer::translate" which I am hoping will do what you need. Otherwise I will need to revisit things and use the code from the core that dynamically generates the page names on the fly from the titles. I have also added a few new features to this module: There is a new "Add" option so it is possible to bulk add new children regardless of the content and grandchildren of the other sibling pages. Also there is a new config setting for allowing you to override the content protection check when using the overwrite mode - obviously use with extreme caution. Hope all those changes are useful. First post updated with new options and screenshots.1 point
-
There is this one from Soma: https://processwire.com/talk/topic/5895-sev-online-relaunch/1 point
-
Thanks guys for stepping in! Slapped my forehand a few times with that one This hidden gem is truly a hidden gem1 point
-
Exactly my thought. And loaded/configurable per template, so that only hanna codes are shown that makes sence in that template.1 point
-
has_parent isn't supported for runtime filtering with a path, not("selector") is filtering the results from the returned WireArray, there "has_parent" isn't supported in the same way as in a find selector. There's a path is converted to the ID before running the query. Regarding performance and such your second example is the way to go.1 point
-
Yep, what Martijn said or read here from the Reiska himself https://processwire.com/talk/topic/163-images-and-thumbnails/?p=11601 point
-
See the cheatsheet. Usually you use this to change values on pages and save them through the API. I don´t know why to use it here. Kongondo might explain that1 point
-
I was just curios about how fast PHP handles the different types of string concatenation/parsing with variables, because I saw Ryan's style is double quotes and I was thinking, isn't that slower than single quote concatenation? I was surprised because I remember to have learned that the additional parsing of double quote strings make the whole thing slower. I was wrong, here is my benchmark. Thought it'd be interesting to know. 1000000 times per test // initial object creation, only once $fooObject = new stdClass; $fooObject->foo = "Lorem ipsum dolor sit amet."; $fooObject->bar = "Consectetur adipisicing elit."; $fooObject->baz = "Sed do eiusmod tempor incididunt."; double quotes "foo: {$fooObject->foo}, bar: {$fooObject->bar}, baz: {$fooObject->baz}" 0.55859899520874 s single quotes concat 'foo: ' . $fooObject->foo . ', bar: ' . $fooObject->bar . ', baz: ' . $fooObject->baz 0.61702013015747 s sprintf sprintf("foo: %s, bar: %s, baz: %s", $fooObject->foo, $fooObject->bar, $fooObject->baz) 1.6139810085297 s array implode implode('', array('foo: ', $fooObject->foo, ', bar: ', $fooObject->bar, 'baz: ', $fooObject->baz)) 2.0107381343842 s Code: <?php $times = 1000000; ?> <h1>PHP string concat benchmark</h1> <p><?=$times?> times per test</p> <code><pre> $fooObject = new stdClass; $fooObject->foo = "Lorem ipsum dolor sit amet."; $fooObject->bar = "Consectetur adipisicing elit."; $fooObject->baz = "Sed do eiusmod tempor incididunt."; </pre></code><br> <hr> <?php function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } $fooObject = new stdClass; $fooObject->foo = "Lorem ipsum dolor sit amet."; $fooObject->bar = "Consectetur adipisicing elit."; $fooObject->baz = "Sed do eiusmod tempor incididunt."; $time_start = microtime_float(); for ($i=0; $i < $times; $i++) { $someString = "foo: {$fooObject->foo}, bar: {$fooObject->bar}, baz: {$fooObject->baz}"; } $time_end = microtime_float(); $time = $time_end - $time_start; ?> <h2>double quote</h2> <code>"foo: {$fooObject->foo}, bar: {$fooObject->bar}, baz: {$fooObject->baz}"</code><br><br> <?=$time?> s<br><br> <hr> <?php $time_start = microtime_float(); $someString = ''; for ($i=0; $i < $times; $i++) { $someString = 'foo: ' . $fooObject->foo . ', bar: ' . $fooObject->bar . ', baz: ' . $fooObject->baz; } $time_end = microtime_float(); $time = $time_end - $time_start; ?> <h2>single quote concat</h2> <code>'foo: ' . $fooObject->foo . ', bar: ' . $fooObject->bar . ', baz: ' . $fooObject->baz</code><br><br> <?=$time?> s<br><br> <hr> <?php $time_start = microtime_float(); for ($i=0; $i < $times; $i++) { $someString = sprintf("foo: %s, bar: %s, baz: %s", $fooObject->foo, $fooObject->bar, $fooObject->baz); } $time_end = microtime_float(); $time = $time_end - $time_start; ?> <h2>sprintf</h2> <code>sprintf("foo: %s, bar: %s, baz: %s", $fooObject->foo, $fooObject->bar, $fooObject->baz)</code><br><br> <?=$time?> s<br><br> <hr> <?php $time_start = microtime_float(); for ($i=0; $i < $times; $i++) { $someString = implode('', array('foo: ', $fooObject->foo, ', bar: ', $fooObject->bar, 'baz: ', $fooObject->baz)); } $time_end = microtime_float(); $time = $time_end - $time_start; ?> <h2>array implode</h2> <code>implode('', array('foo: ', $fooObject->foo, ', bar: ', $fooObject->bar, 'baz: ', $fooObject->baz))</code><br><br> <?=$time?> s<br><br>1 point
-
Just a quick update, I've now got some code to show, to explain exactly what I mean. I've set up some pages which will act as forum categories. These use a template called forum_cat. I have also set up a page field called forum_access which is attached to this template. The forum_access field has the parent admin/access/Roles so that I can select which roles are allowed to view that forum category. $forumCategories = $pages->find("template=forum_cat"); foreach($forumCategories as $forumCategory) { foreach($forumCategory->forum_access as $forumAccess) { if($user->roles->has($forumAccess)) { echo $forumCategory->title; break; } } } } So back to the original question, is this just as safe as using a standard permission? I want to do it this way so that each forum category acts as a setting page for that particular category. Thanks again.1 point
-
like it! added $(function() { $( ".ace-editor-position-wrapper .ace_scroller" ).resizable({ alsoResize: ".ace-editor-design-wrapper", minWidth: 1145, maxWidth: 1145 }); }); at the very end of InputfieldAceEditor.js Is there a way adding buttons to the editor especially the pwimage button like in tinymce? I know, ace doesn´t handle inline images in editor but how about just inserting the html/mardown/textile for the selected image? cheers Can PS: it´s working in 2.4 as well1 point
-
I have never even considered using anything like Hanna code or shortcodes for our clients. I think what would make them usable would be making them appear as a block in editor, instead of plain text.1 point
-
You're welcome. It's always a pleasure to be able to help someone. I'd suggest you (and everyone else for that matter!) take a look at Soma's great Cheatsheet. Click around and discover something new for your toolbox.1 point
-
Somehow this sounds like a repeater issue, though I can't quite wrap my head around it -- probably too tired at the moment. I'd still start by making sure that those repeaters really are fine, perhaps re-creating the repeater field itself, and/or making sure that the actual repeater pages under admin (/processwire/repeaters/repeater-field-name/page-name/repeater-item/) are published etc. Wouldn't be the first time that something goes wrong there.1 point
-
I believe that once you set the access to the template, it will affect what is searched (i.e search results).1 point
-
Does the search or search results template have any caching enabled on it?1 point
-
I had to figure this out as well. If you are using the thumbnail module, you won't need to define your width and height as variables in the template. See if this works. Instead of foreach($images as $image) { $thumb = $image->size($thumbWidth, $thumbHeight); try foreach($images as $image) { $thumb = $image->getThumb('thumbnail'); Then your <img src="<?= $thumb->url ?>" should change to <img src="<?= $thumb ?>" That might work.1 point
-
Well, I read through your code a week back but couldn't spot any obvious flaw. Now I had another look and feel like I should've seen it in the first place... Actually you did yourself in the very beginning as you had the very same problem then. You're welcome. And you should still hang on to what you had working . Here's the problem line (core of it anyway): $matches = $all->find("rental_period.date_from>=$df, rental_period.date_to<=$dt, rental_period.booked=0"); As you figured out before (and Ryan confirmed you right), this kind of selector is something to beware of. While all of the three conditions must match, they only have to match the same page (property_availability), not the same repeater item. So this would match any page that has rental_period-repeater with one item matching the condition for date_from, another item matching the condition for date_to and third item matching the condition for booked. All the conditions could have a match in the very same repeater item, but that's not required (and you'd want it to be). That's just the nature of repeaters. Nasty, I know. Take the version with working date ranges and add the capacity and region handling like you have now in the beginning. Then, instead of first finding all cottages matching region and capacity, just go for the repeater items matching the date range like before and modify the match handling like this: foreach($matches as $item) { $property = $item->getForPage(); if(!$property->viewable()) continue; // skip if property is unpublished or something // add this: skip the match if it doesn't match your region or capacity if(!$property->matches($filterSelector)) continue; // now you have the $property and the matching repeater $item $termCottages[] = $item->id; } Here $filterSelector should be empty if no region or capacity has been chosen. Or it could be something like "location=xyz, sleeps>=10" to rule out any cottages not located in xyz or having capacity of less than 10. I haven't tested it but naturally it'll work like a charm . So you were on the right track all along. Just don't go for something that's been proven faulty for this scenario before.1 point
-
I've a second issue regarding the size-limiting. It seems, that system-templates aren't supported. So the sizes won't be displayed, if you use them for user-profiles. EDIT: Ok found the error. The template names need to start right after the comma, while the dimensions also work with leading spaces. Maybe a trim could be implemented to remove those spaces, as they're a illigal characters for templates, too.1 point
-
Hey, just wanted to tell you that my new tech blog (which gonna be a little bit like flamingruby.com in worse english) has finally a name and a new design. And this sweet animated icon It's not completely finished but the main design is ready. Responsive and some bugfixes will follow. What do you think: http://supercode.co/ -- nico1 point
-
1 point
-
The notices system actually doesn't have anything to do with jQuery UI other than that the default admin theme makes use of jQuery UI class names when generating the markup for notices. But for your own front-end, you can make use of the $notices API variable to output them however you want. It can be as simple as this: echo "<ul>"; foreach($notices as $notice) { $class = $notice->className(); $text = $sanitizer->entities($notice->text); echo "<li class='$class'>$text</li>"; } echo "</ul>"; Then you would want to style the two type of notices in your CSS: .NoticeMessage { color: green; } .NoticeError { color: red; }1 point
-
Updated this to support localized day titles and simple prev/next navigation. <?php function renderCalendar($page, $year, $month, $field = 'startdate') { // This feels little dirty, there is probably much more efficient way to get local day name? $mon = strftime('%a', strtotime("2011-11-14 00:00:00")); $tue = strftime('%a', strtotime("2011-11-15 00:00:00")); $wed = strftime('%a', strtotime("2011-11-16 00:00:00")); $thu = strftime('%a', strtotime("2011-11-17 00:00:00")); $fri = strftime('%a', strtotime("2011-11-18 00:00:00")); $sat = strftime('%a', strtotime("2011-11-19 00:00:00")); $sun = strftime('%a', strtotime("2011-11-20 00:00:00")); $year = (int) $year; $month = (int) $month; $startTime = strtotime("$year-$month-01 00:00:00"); $endTime = strtotime("+1 month", $startTime); $lastMonth = strtotime("-1 month", $startTime); // find all events that fall in the given month and year $events = $page->children("$field>=$startTime,$field<$endTime"); // get all the info you need to draw a grid calendar $weekDayNames = array($mon, $tue, $wed, $thu, $fri, $sat, $sun); $firstDayName = strftime('%a', $startTime); // i.e. "Tue" (Eng) or "ti" (Fin) $daysInMonth = date('t', $startTime); // 28 through 31 // make the calendar headline $out = "<h1>" . strftime('%B %Y', $startTime) . "</h1>"; // i.e. October 2011 $out .= "<div class='nav'>"; $out .= "<a href='../../". date('Y', $lastMonth) ."/". date('m', $lastMonth) ."/'>←</a>"; $out .= "<a href='../../". date('Y', $endTime) ."/". date('m', $endTime) ."/'>→</a>"; $out .= "</div>"; // create the calendar header with weekday names $out .= "<table class='calendar'><thead><tr>"; foreach($weekDayNames as $name) $out .= "<th>$name</th>"; $out .= "</tr></thead><tbody><tr>"; // fill in blank days from last month till we get to first day in this month foreach($weekDayNames as $name) { if($name == $firstDayName) break; $out .= "<td> </td>"; } // draw the calendar for($day = 1; $day <= $daysInMonth; $day++) { // get the time info that we need for this day $startTime = strtotime("$year-$month-$day 00:00:00"); $endTime = strtotime("+1 day", $startTime); $dayName = strftime('%a', $startTime); // if we're at the beginning of a week, start a new row if($day > 1 && $dayName == $mon) $out .= "<tr>"; // create the list of events for this day (if any) $list = ''; foreach($page->children("$field>=$startTime, $field<$endTime") as $event) { $list .= "<li><a href='{$event->url}'>{$event->title}</a><p>{$event->location->title}, <span class='city'>{$event->location->city->title}</span></p></li>"; } // if any events were found for this day, wrap it in <ul> tag if($list) $list = "<ul>$list</ul>"; // make the day column with day number as header and event list as body $out .= "<td valign='top'><h2>$day</h2>$list</td>"; // if last day in week, then close out the row if($dayName == $sun) $out .= "</tr>"; } // finish out the week with blank days for next month $key = array_search($dayName, $weekDayNames); while(isset($weekDayNames[++$key])) { $out .= "<td> </td>"; } // close the last row and table $out .= "</tr></tbody></table>"; // output the calendar return $out; }1 point
-
Here was Ryan's example code for calendar, until I (apeisa) modified it instead of quoting... I got the original back from my editor, I post it here as reference. Ryan - sorry I lost your message here. You wrote something about that it is fun to code calendars -apeisa <?php $year = (int) $input->urlSegment1; $month = (int) $input->urlSegment2; if(!$month) $month = date('n'); // if no month, use this month if(!$year) $year = date('Y'); // if no year, use this year $startTime = strtotime("$year-$month-01 00:00:00"); $endTime = strtotime("+1 month", $startTime); // find all events that fall in the given month and year $events = $page->children("date>=$startTime, date<$endTime"); // get all the info you need to draw a grid calendar $weekDayNames = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'); $firstDayName = date('D', $startTime); // i.e. Tue $daysInMonth = date('t', $startTime); // 28 through 31 // make the calendar headline $out = "<h1>" . date('F Y') . "</h1>"; // i.e. October 2011 // create the calendar header with weekday names $out .= "<table><thead><tr>"; foreach($weekDayNames as $name) $out .= "<th>$name</th>"; $out .= "</tr></thead><tbody><tr>"; // fill in blank days from last month till we get to first day in this month foreach($weekDayNames as $name) { if($name == $firstDayName) break; $out .= "<td> </td>"; } // draw the calendar for($day = 1; $day <= $daysInMonth; $day++) { // get the time info that we need for this day $startTime = strtotime("$year-$month-$day 00:00:00"); $endTime = strtotime("+1 day", $startTime); $dayName = date('D', $startTime); // if we're at the beginning of a week, start a new row if($day > 1 && $dayName == 'Sun') $out .= "<tr>"; // create the list of events for this day (if any) $list = ''; foreach($events->find("date>=$startTime, date<$endTime") as $event) { $list .= "<li><a href='{$event->url}'>{$event->title}</a></li>"; } // if any events were found for this day, wrap it in <ul> tag if($list) $list = "<ul>$list</ul>"; // make the day column with day number as header and event list as body $out .= "<td><h2>$day</h2>$list</td>"; // if last day in week, then close out the row if($dayName == 'Sun') $out .= "</tr>"; } // finish out the week with blank days for next month $key = array_search($dayName, $weekDayNames); while(isset($weekDayNames[++$key])) { $out .= "<td> </td>"; } // close the last row and table $out .= "</tr></tbody></table>"; // output the calendar echo $out;1 point