Leaderboard
Popular Content
Showing content with the highest reputation on 11/26/2013 in all areas
-
Template Notes Adds a "Help" tab to pages for notes and instructions on the current template used. You can add content by simply putting a html or markdown file in /site/templates/notes/ the module will automatically load that file if it finds one and adds a "Help" tab to the page edit form. Name the files using the template name. You can use html or markdown to write the help text. - /site/templates/notes/[tplname].html - /site/templates/notes/[tplname].md To style the content you can specify a custom css file url you add to the module settings. http://modules.processwire.com/modules/template-notes/ https://github.com/somatonic/TemplateNotes This module was quickly written after seeing a wish-list request by Joss http://processwire.com/talk/topic/5016-help-tab-for-template/8 points
-
good one I also wrote about in some thread... and for those being even more lazy can also use the even shorter $page->is(selector) if($page->is('template=template1|template2|template3|template4')){ edit: or if just for one template instead if($page->template == "basic-page"){ use if($page->is("basic-page")){2 points
-
Thinking of it now, it doesn't seem that difficult to do this with PW. Instead of thinking of different templates on each repeater we can just have a repeater with a field or more for each kind of content. If those fields are filed the code knows what to do with them: foreach($page->repeater as $r) { if($r->image->url) { // image block; } elseif ($r->text) { // text block; } } May sound confusing to have many fields on a repeater block and tell the client to fill only one or two, but now we have http://processwire.com/talk/topic/4323-field-dependencies/, so we just have to put a radio button with all our "templates" at the beggining and show the related field groups accordingly. This will make our guessing work even easier: foreach($page->repeater as $r) { switch ($r->radio->name) { case "image": // image block case "text": // text block case "quote": // quote block } }2 points
-
I just looked into this again and there's no argument for removeAll() just for remove($key). See here in source https://github.com/ryancramerdesign/ProcessWire/blob/dev/wire/core/WireArray.php#L790 removeAll() removes ALL pages from a Wire/PageArray (pages, images, POST vars etc). So I'm not sure about why it works for you because it shouldn't and also doesn't work for me. Assuming user_app is a page field allowing multiple pages to be selected. It's a WireArray/PageArray and you add pages to it like this from API: $user->of(false); $page1 = $pages->get("/somepage/"); $page2 = $pages->get("/someotherpage/"); $user->user_app->add($page1); $user->user_app->add($page2); $user->save(); Now we got 2 pages added to the page field. If you now do a $page->user_app->removeAll($page1) they all get removed so does $user->user_app->removeAll(); But if you do: $page2 = $pages->get("/someotherpage/"); $user->user_app->remove($page2); $user->of(false); $user->save(); Now only the $page2 which is in the array gets removed. It works all as expected and make sense.2 points
-
I think Pete was right actually - the way I see it, the API, coupled with templates and fields, essentially, is your ORM An ORM is just an abstraction on top of a database which makes the data easy to work with. Your database contains your tables, columns and rows of data. In ProcessWire, your rows are pages; your columns are fields, and your tables are templates (roughly!). So to interact with those, you use the API. Relational data can be handled by using the Page reference fieldtype, for example. Having said that, if you have a desperate need to use something other than ProcessWire to manage some data, it is just PHP. Find an ORM you like, include() it, and start using it within your site as and when you need to.2 points
-
My solution, which works nicely: I put the following code on the top of my template. (example for French as default, German and English) $date_lang = array(); switch ($user->language->name) { case 'en': setlocale(LC_ALL, 'en_GB'); $date_lang[0] = "%A %B %eth %Y at %I:%M %p"; $date_lang[1] = "%B %eth %Y"; $date_lang[2] = "%I:%M %p"; $date_lang[3] = "%A"; break; case 'fr': setlocale(LC_ALL, 'fr_FR'); $date_lang[0] = "%A %e %B %Y à %kh%M"; $date_lang[1] = "%e %B %Y"; $date_lang[2] = "%kh%M"; $date_lang[3] = "%A"; break; case 'de': setlocale(LC_ALL, 'de_DE'); $date_lang[0] = "%A, den %e. %B %Y um %k.%Mh"; $date_lang[1] = "%e. %B %Y"; $date_lang[2] = "%k.%Mh"; $date_lang[3] = "%A"; break; default: setlocale(LC_ALL, 'fr_FR'); $date_lang[0] = "%A %e %B %Y à %kh%M"; $date_lang[1] = "%e %B %Y"; $date_lang[2] = "%kh%M"; $date_lang[3] = "%A"; } Then I created a page field, where I store a date unformatted (go to setup->fields->mydatefield->details-> date output format ->"None"). getUnformatted() is only needed, if the date is stored formatted. Finally I can insert the date like echo strftime($date_lang[0], $mydatefield); /* output(de): Freitag, den 11. Oktober 2013 um 12.52h * output(fr): Vendredi 11 octobre 2013 à 12h46 * output(en): Friday October 11th 2013 at 12:46 pm */ echo strftime($date_lang[1], $mydatefield); /* output(de): 11. Oktober 2013 * output(fr): 11 octobre 2013 * output(en): October 11th 2013 */ echo strftime($date_lang[2], $mydatefield); /* output(de): 12.52h * output(fr): 12h52 * output(en): 12:52 pm */ echo strftime($date_lang[3], $mydatefield()); /* output(de): Freitag * output(fr): Vendredi * output(en): Friday */ Maybe you have to check out which string in setlocale is working on your Server. Try different: setlocale(LC_ALL, array('fi_FI.UTF-8','fi_FI@euro','fi_FI','finnish')); //put out the first supported string echo setlocale(LC_ALL, 0);2 points
-
I found (after 2-3 Projects using PW) that it's a good technique to use templates in a way I think hasn't been thought of yet really by some. (Although the CMS we use at work for year, works this way.) I'm sure I'm maybe wrong and someone else is already doing something similar. But I wanted to share this for everybody, just to show alternative way of using the brillant system that PW is. Delegate Template approach I tend to do a setup like this: - I create a main.php with the main html markup, no includes. So the whole html structure is there. - I then create page templates in PW without a file associated. I just name them let's say: basic-page, blog-entry, news-entry... but there's no basic-page.php actually. - Then after creating the template I make it use the "main" as alternative under "Advanced" settings tab. So it's using the main.php as the template file. - This allows to use all templates having the same php master template "main.php" - Then I create a folder and call it something like "/site/templates/view/", in which I create the inc files for the different template types. So there would be a basic-page.inc, blog-entry.inc ... - Then in the main.php template file I use following code to delegate what .inc should be included depending on the name of the template the page requested has. Using the TemplateFile functions you can use the render method, and assign variables to give to the inc explicitly, or you could also use just regular php include() technic. <?php /* * template views depending on template name * using TemplateFile method of PW */ // delegate render view template file // all page templates use "main.php" as alternative template file if( $page->template ) { $t = new TemplateFile($config->paths->templates . "view/{$page->template}.inc"); //$t->set("arr1", $somevar); echo $t->render(); } <?php /* * template views depending on template name * using regular php include */ if( $page->template ) { include($config->paths->templates . "view/{$page->template}.inc"); } I chosen this approach mainly because I hate splitting up the "main" template with head.inc and foot.inc etc. although I was also using this quite a lot, I like the delegate approach better. Having only one main.php which contains the complete html structure makes it easier for me to see/control whats going on. Hope this will be useful to someone. Cheers1 point
-
Hi all! I have created this new module that improve the current search engine on PW: https://github.com/USSliberty/Processwire-site-indexer (Beta version) The main idea is to create an hidden field that store keywords (separated by space). The keywords are generated automatically from all text fields in the page, plus PDFs and DOCs files. So if you create new text fields you can forget to add they on Search Page Module. The only thing to do after install, is to change the list of fields in Search Page (see attachment). In fact you need to search only in "indexer" field. NOTE 1: At this time the module index only when you save the page. In the next week maybe i will add the complete-site re-index. NOTE 2: The files are indexed with 2 Unix packages (poppler-utils & wv). I have tried without success with pure PHP classes, but if know a class that works fine i can add it into module. ADB1 point
-
1 point
-
Ah, cool. The cheatsheet says that "matches" matches the selector, whilst "is" matches template, status or selector. And for those that haven't read the Cheatsheet by now, here you go: http://cheatsheet.processwire.com/ Soma - I feel like we've just taught a class or something1 point
-
And for those that don't know, you can do this in ProcessWire if you want to match against multiple templates, like this: if ($page->matches('template=template1|template2|template3|template4')) { ... instead of this: if ($page->template == 'template1' || $page->template == 'template2' || $page->template == 'template3' || $page->template == 'template4') { ... Just thought that was worth sharing as I was typing it the long-hand PHP way just now and stopped myself before I wrote a lot of extra characters for no real reason! A shorter PHP alternative than above would be this: if (in_array($page->template, array('template1', 'template2', 'template3', 'template4')) { ... but I much prefer the ProcessWire version. $page->matches is a lovely thing that can be used to test the current page against any selector you can think of that makes sense in your situation.1 point
-
Just for the record and for those wondering what $event->replace = true; does: It prevents the hooked function to get executed when you use addHookBefore().1 point
-
Thanks again Soma, I feel like an idiot right now having the status as a string (not done it anywhere else in my modules so was just being blind ). All working now - for those interested, this is the final code: public function init() { $this->pages->addHookBefore('trash', $this, 'preservePages'); $this->pages->addHookBefore('delete', $this, 'preservePages'); } public function preservePages(HookEvent $event) { $page = $event->arguments[0]; if ($page->template == 'template-name') { $page->addStatus(Page::statusHidden); $page->save(); $event->replace = true; $this->message("The page was hidden instead of deleted. Pages using the '" . $page->template . "' template can be linked to other pages, so deleting is prohibited"); } } As you can see, much simpler after Soma's expert help. @Soma: I can't mark both your replies as the Solved post, so will have to mark this one with the full code if that's okay?1 point
-
not as a string should work... $page->addStatus(Page::statusHidden); Cheers1 point
-
how about public function preservePages(HookEvent $event) { $event->replace = true; ... Thanks for the beer. Really strange that you can't just remove permission to delete pages, for what reason? Feels weird when deleting page and it just gets hidden.1 point
-
Hi Niklas, i guess maybe when you say 'sites' you mean pages? this is something that can already be done pretty easily. for example i just did a site with 3 distinct types of data, classes (as in like an art class), sessions (as in the actual session that the class runs, start/end dates, instructor etc.) and events. For the classes, we setup a parent page called Class Database, and then a custom admin page for viewing the list of classes, and being able to click on one and edit it. the class database page used a template called class-database which only allows the page type class as a child. for sessions those are relational to classes and output on each class, the class is a page select on the session, and there is no template file for the session, so they won't show or be accessible on the front end. the classes are output using url segments and some url 'rewriting' logic that was demonstrated by Ryan's CMS Critic case study.1 point
-
Hi jdiderick, Thank you for the addition! I will release a new version soon with your code and some other improvements. ADB1 point
-
We already got through this guys .... Here http://processwire.com/talk/topic/4189-flexibility-in-page-design/?p=47083 and here above on this page http://processwire.com/talk/topic/4189-flexibility-in-page-design/?p=470851 point
-
1 point
-
Thanks Zahari! MyFonts has always great deals here http://www.myfonts.com/specials/. It's a great page to check out from time to time. edit: the forum does the very irritating thing of including the punctuation dots on the urls when there is one (in this case I edited to correct). Would be so easy to exclude them when doing the string replace, or whatever method is used...1 point
-
1 point
-
1 point
-
1 point
-
Setting a class which disables pointer events while scrolling = no more (re)paints when accidentally hovering elements <3 http://www.thecssninja.com/javascript/pointer-events-60fps1 point
-
1 point
-
Nice one Soma. I was thinking of a more complicated solution earlier, so +1 for keeping it simple and effective as these notes only need to be written once per template by the person building the site really1 point
-
Not sure here but how do you expect the zipped images to be displayed in the select image dialog ? Some background service or property/config of your editor ? Anyway, did you check write permissions for your file path /site/assets/files/ ? To check if your hosting server accepts automatic unzipping run the following script: first specify a directory to unzip the files to make sure this directory has write permissions <?php $zip = new ZipArchive; $res = $zip->open('my_zip_file.zip'); if ($res === TRUE) { $zip->extractTo('my_extract_to_dir/'); $zip->close(); echo 'ok'; } else { echo 'failed'; } ?>1 point
-
+1 good found. Useful and practical to keep track of structure of larger sites and keeping a history of edits.1 point
-
1 point
-
i use this a lot: http://processwire.com/talk/topic/3429-how-to-set-text-linecharacter-limits-in-templates/?p=337791 point
-
@martijn - cool, yeah i've done some similar things like that, but your suggestion is really good for having all the settings for each slide layer in it's own little textarea; each slide is a page and then i could use a repeater for each slide layer and then have a text box for style attributes which control the animation... still doesn't really solve the putting of php directly into the editor though... i've seen plugins for other cms that enable one to put php into text area, one that i remember using a lot was sourcerer from nonumber.nl1 point
-
Hey Alessio, Love the module, works great. I missed one thing though... Page fields. I use Page fields regularly to make for example references to Genres, Categories, Countries etc. So I added some code to also add the pagenames of the pages in Page fields. I created a pull reguest on Github to add this change to your code. For those wanting to try this out, replace the extractTextFromField function in Indexer.module with this one or just add the elseif() part (start line 372) to it: public function extractTextFromField($f, $p){ if( preg_match('/text|title|url/i', $f->type) && $p->editable($f->name) && $f->name != self::fieldName ): $stripped = strip_tags($p->get($f->name)); return ' '.$stripped; elseif( preg_match('/page/i', $f->type) && $p->editable($f->name) && $f->name != self::fieldName ): $stripped = ""; $f_ref = $p->get($f->name); if($f_ref instanceOf PageArray){ foreach($f_ref as $fp){ $stripped .= ' '.strip_tags($fp->name); } }else{ $stripped .= ' '.strip_tags($f_ref->name); } return $stripped; endif; }1 point
-
1 point
-
FormBuilder is also a good way to go for contact forms, especially if you want to set one up without doing any development and have a lot of pre-bundled options as to where the submitted data goes.1 point
-
Had fun to create a webfont with only one single glyph: Processwire-Logo Unicode-Letter: (Unicode Block "For Private Use") I created first an svg with inkscape and created the font-set with http://icomoon.io/app (very nice website!) Like it, use it, waste it. font-package with demo file here: attachment=1836:processwire_webfont.zip updated 23.11.13 (4 Glyphs: 'processwire', 'process', 'wire' and 'w') processwire_webfont.zip1 point
-
1 point
-
Looks like, jQuery cannot find the reference to this $('#RenameRules .InputfieldContent:first'), that's why the button is never added to the DOM Hope this can't be fixed Cheers1 point
-
Just pushed an update to 1.0.5 to fix issues once again (!) - updated to account for current new development on admin theme - some optimizations - kinda fixed an issue with the new LanguageFieldsTabs. - It was getting overlayed by the tabs. Also the LanguageFieldTabs alters the field content via JS and appends the tabs, which results in my Helper links being at the top instead at the bottom! Annoying and not possible to fix from my side, but if LanguageFieldTabs.js would prepend() the tabs instead of append() it would be better. I don't see an easy way to account for this issue from my side, maybe someone has an good idea. - but for now it's on top of those fields using language tabs. - added new feature to toggle a layer when clicking on the little gear icon, with some infos on the field settings, which can be useful when developing without going to the field editing screen. There maybe still issues in some cases I haven't tested or thought of. Thanks1 point
-
What version of ProcessWire? you might try fixing it manually by locating the page through the page list tree via Admin > Pages > Repeaters > ...1 point
-
1 point
-
With template files you generally have a documented set of API variables ($page, $pages, $user, etc.), and this is what the set() methods of TemplateFile are geared towards. On the other hand, when passing variables into a $page->render(), variables passed in may be unknown/undocumented to the template file, and will be installation-specific, since PW doesn't pass in API variables that way. By having them in a known array ($options), you have a way of inspecting them, or at least knowing where they will be. Otherwise, the template file would have no means of self discovery for these things. It decreases the unknowns, increases the portability, and introduces an appropriate level of separation from the system API variables. On the other hand, this is largely theoretical… I've never had the need to pass in variables to template files in this manner, so am mainly just trying to accommodate the needs brought up in this thread.1 point
-
Thanks for posting Soma, this is an interesting approach and not one I've seen before, but it looks great. The underlying concept and result is similar to the approach I usually use. Since you posted a good description, I'll try to do the same for mine. The only reason you see head/foot files in the default PW profile is because it seems to be simpler for new users to grasp. But I almost never use that approach in my own sites. Like your system, I have a main.php file which is my main markup file. But unlike your system, main.php is included from all the other template files (rather than main.php including them). The other template files focus on populating the key content areas of the site, specific to the needs of the template. Examples of key content areas might include "main" (for center column/bodycopy) and "side" (for sidebar/related info), though often includes several other identified areas. But I'll keep it simple in this case. Here's how it works: basic-page.php <?php $outMain = "<h2>{$page->subtitle}</h2>" . $page->body; if($page->numChildren) $outMain .= $page->children->render(); // list the children $outSide = $page->sidebar; include("./main.php"); main.php <html> <head> <title><?php echo $page->title; ?></title> </head> <body> <h1><?php echo $page->title; ?></h1> <div id='main'><?php echo $outMain; ?></div> <div id='side'><?php echo $outSide; ?></div> </body> </html> The benefit of this approach is that basic-page.php can setup whatever it wants in the key content areas ($main or $side) whether simple like in this example, or something much more complex. I actually prefer for the variables representing the key content areas to be optional. In the scenario above, $outMain and $outSide would have to be defined by every template or they would end up as uninitialized variables in main.php. As a result, I actually use $page as an anonymous placeholder for these variables (making sure they don't conflict with any existing field names) and then let main.php assign defaults if the calling template didn't specify one of them. For example: basic-page.php <?php $page->outMain = "<h2>{$page->subtitle}</h2>" . $page->body; if($page->numChildren) $page->outMain .= $page->children->render(); // list the children // note: no $outSide specified include("./main.php"); main.php <?php // setup defaults when none specified if(empty($page->outMain)) $page->outMain = $page->body; if(empty($page->outSide)) $page->outSide = $page->sidebar; ?> <html> <head> <title><?php echo $page->title; ?></title> </head> <body> <h1><?php echo $page->title; ?></h1> <div id='main'><?php echo $page->outMain; ?></div> <div id='side'><?php echo $page->outSide; ?></div> </body> </html> Final thing to point out here is that main.php is the only template actually outputting anything. Because basic-page.php (or any other template) is determining what's going to go in that output before it is actually sent, your template has the opportunity to modify stuff that you might not be able to with other methods. For instance, the <title> tag, what scripts and stylesheets are loaded, etc. Here's the example above carried further to demonstrate it: basic-page.php <?php // make a custom <title> tag $page->browserTitle = $page->rootParent->title . ": " . $page->title; $page->outMain = "<h2>{$page->subtitle}</h2>" . $page->body; if(count($page->images)) { // display a clickable lightbox gallery if this page has images on it $config->scripts->add($config->urls->templates . "scripts/lightbox.js"); $config->styles->add($config->urls->templates . "styles/gallery.css"); $page->outMain .= "<ul id='gallery'>"; foreach($page->images as $i) { $t = $i->size(100,100); $page->outMain .= "<li><a href='{$i->url}'><img src='{$t->url}' alt='{$t->description}' /></a></li>"; } $page->outMain .= "</ul>"; // add a note to $page->title to say how many photos are in the gallery $page->title .= " (with " . count($page->images) . " photos!)"; } if($page->numChildren) $page->outMain .= $page->children->render(); // list the children include("./main.php"); main.php <?php // if current template has it's own custom CSS file, then include it $file = "styles/{$page->template}.css"; if(is_file($config->paths->templates . $file)) $config->styles->add($config->urls->templates . $file); // if current template has it's own custom JS file, then include it $file = "scripts/{$page->template}.js"; if(is_file($config->paths->templates . $file)) $config->scripts->add($config->urls->templates . $file); ?> <html> <head> <title><?php echo $page->get('browserTitle|title'); // use browserTitle if there, otherwise title ?></title> <?php foreach($config->styles as $url) echo "<link rel='stylesheet' type='text/css' href='$url' />"; foreach($config->scripts as $url) echo "<script type='text/javascript' src='$url'></script>"; ?> </head> <body> <h1><?php echo $page->title; ?></h1> <div id='main'><?php echo $page->get('outMain|body'); // use outMain if there, or body otherwise ?></div> <div id='side'><?php echo $page->get('outSide|sidebar'); // use outSide if there, or sidebar otherwise ?></div> </body> </html> More than half the time, I'll actually just re-use page variables like $page->body and $page->sidebar rather than $page->outMain and $page->outSide. That way there's no need to consider defaults, since $page->body and $page->sidebar untouched technically are defaults. <?php $page->body = "<h2>{$page->subtitle}</h2>" . $page->body . $page->children->render(); But technically you've got a little more flexibility using your own self-assign anonymous variables like outMain and outSide, so figured I'd use that in the examples above. outMain and outSide are just example names I came up with for this example and you could of course name them whatever you want.1 point