Leaderboard
Popular Content
Showing content with the highest reputation on 03/21/2012 in all areas
-
Jasper, I just send you a pull request for this module. I added few minor features: Checks publish dates right after saving, and keeps page unpublished if required. Made module configurable to choose cron interval Simplified the code little bit (took 2 unnecessary foreach loops out). I had earlier done this kind of stuff on selector level, but this is much nicer - shows scheduled pages as unpublished on admin pagetree also.2 points
-
Currently datetime can only be used for dates which has unix timestamp 0 or above. I noticed this when tried to use datetime field as birthday-field. I guess this would be pretty easy fix to allow pre-1970 dates also? Using signed integer field on database and allow negative values to be saved.1 point
-
Continuing from the Repeaters thread about the field-template context… This video demonstrates how you can adjust the admin context of individual fields according to the template they are placed in. When you adjust the context in this manner, it only changes the settings for when a field appears in that template. This expands the reusability potential of fields across different templates, hopefully preventing the need to create another field if all you really needed was a different title, description or width. You can do this same type of configuration when editing a field in a repeater too. View this full screen which should put YouTube into HD mode, where it's much easier to see.1 point
-
It looks like this is a new issue that came as a result of our recent fix for the links not being editable in some instances. A text() in jQuery needed to be an html() instead -- easy fix. Just committed. This one I can't duplicate. Though if it was possibly related to the other issue, then that may be why. Let me know if it still does it to you after the other issue is fixed, and if so, in what browser (I tested in Chrome 17). Thanks, Ryan1 point
-
Updated to support negative values in the timestamp, and committed. It had to do with validation rather than the DB field type. We're using a MySQL datetime field for storage, so that isn't bound to the limits of timestamps. We're using timestamps just on the PHP side for sortability, sanitization and abstraction from a defined date format.1 point
-
In that fictional example there are two find() operations, so those aren't going to happen in 1 query, unless the results of 1 are already cached. If I recall, this should work (though not at a place to double check): $pages->find("question.name=yes"); But I want to point out that query counting is usually a waste of time. And I used to do a lot of it, up until I read High Performance MySQL. MySQL will execute a 100 simple queries faster than it will 1 heavy one. So performance usually has much more to do with query quality and proper indexing than query quantity. This is not the way I was originally taught, and not how I worked for many years, so it took me awhile to get it. You can always $db->query() and join the original example into 1 query, making sure that everything happens using an index, but you may or may not see any tangible benefit for your efforts. If there is some real performance bottleneck that could be resolved by querying directly, I still do it, though it's pretty rare. Also note that layers on top of MySQL are not unlike layers on top of languages. C++ is built on top of Assembler, and PHP is built on top of C++. PW is a layer on top of MySQL and PHP. It's possible to make lower layers perform faster than higher layers, if you know your way around them. Every layer is a compromise that has to be compared against the need. I know my way around MySQL and PHP, and for me PW lets me develop stuff 10x (or more) quickly than I could without it... and it's rare that I think it's costing me anything in performance. But if I had a project where maximizing the performance out of MySQL and PHP took precedence over all other factors, then I would keep out all other layers (no CMS, frameworks or other libraries).1 point
-
1 point
-
Thanks Jasper. It was nice coding, since you had clean and well commented code. About removing the foreach: I don't think I changed any functionality (at least not on purpose). There is still 2 foreach loops, but there were 4 before my commit. You had foreach where you removed certain items from PageArray, and after that another foreach where you published/unpublished those pages. Don't know if that has any real performance advantage, but it makes code shorter. On page save I only check if: a) You have publish_from > publish_until => don't publish, dates don't make any sense b) publish_from > current time => don't publish, even if I try to publish c) publish_until < current time => don't publish, even if I try to publish1 point
-
Ryan, Unfortunately it's a copy/paste/configure scheme, as for codemagic you could integrate it in you PW distro, some might it find helpful (at least I did ). Here are the instructions for manual installation for TinyMCE theme and plugin. Theme installation 1. Unzip futuraremixed-tinymce-theme.zip to /wire/modules/Inputfield/InputfieldTinyMCE/tinymce-3.4.7/themes/advanced/skins/ directory 2. Change option "skin" to "skin: "futuraremixed" in InputfieldTinyMCE.js located in /wire/modules/Inputfield/InputfieldTinyMCE/ directory CodeMagic plugin installation 1. Unzip codemagic-plugin.zip to /wire/modules/Inputfield/InputfieldTinyMCE/tinymce-3.4.7/plugins 2. Go to Setup - Fields and edit your Body field or some other field that uses TinyMCE 3. Select Input tab, select TinyMCE Advanced Configuration Options 4. Under theme_advanced_buttons1 or theme_advanced_buttons1 add codemagic 5. Under plugins add codemagic at the end of the plugins line (separated with comma) I plan to make improvements as you have suggested, search box annoys me sometimes also codemagic-plugin.zip futuraremixed-tinymce-theme.zip1 point
-
I actually have had similar need few times. There is a module for it (maintenance mode: http://processwire.com/talk/topic/382-module-maintenance-mode/) which you can use. I have usually just checked on my templates that if user is not logged in, then display some message or redirect somewhere. But I am not sure why guest view permission is required on home template? Is there some technical requirement for that Ryan?1 point
-
Yeah I think we probably should. Here they are. I've tried to tailor them for cheatsheet format and included an @advanced tag where applicable. I understand the sentences of text don't fit in the cheatsheet, so wasn't sure how you'd want to handle those (or leave them out), but put them here in case helpful. FieldtypeFile or FieldtypeImage can be configured to hold a single file or multiple files. When configured to hold multiple files, it is a WireArray (called Pagefiles or Pageimages) with these additions: <?php $files->path; // Returns the full server disk path where files are stored $files->url; // Returns the URL where files are stored $files->page; // Returns the $page that contains this set of files $files->delete($file); // Removes the file and deletes from disk when page is saved (alias of remove) $files->deleteAll(); // Removes all items and deletes them from disk when page is saved @advanced Each item in the WireArray is a $file or $image (called Pagefile or Pageimage). Likewise, when FieldtypeFile or FieldtypeImage is configured to hold a single file, it is just the $file or $image with the following properties and methods: $file properties <?php $file->url; // URL to the file on the server $file->filename; // full disk path to the file on the server $file->name; // Returns the filename without the path (basename) $file->description; // value of the file's description field (text). Note you can set this property directly. $file->ext; // file's extension (i.e. last 3 or so characters) $file->filesize; // file size, number of bytes $file->filesizeStr; // file size as a formatted string $file->pagefiles; // the $files array that contains this file @advanced $file->page; // the $page that contains this file @advanced (string) $file; // returns the file's name (no path) $file methods <?php $file->rename($name); // Rename this file to the given name (no path). Returns true on success, false on failure. $file->getNext(); // Returns the next file in a multi-file field, or NULL if at the end @advanced $file->getPrev(); // Returns the previous file in a multi-file field, or NULL if at the beginning @advanced When dealing an $image, it is the same as a $file, but with the following additions: $image properties (in addition to those in $file): <?php $image->width; // Width of image, in pixels $image->height; // Height of image, in pixels $image->original; // Reference to original $image, if this is a resized version. @advanced $image methods (in addition to those in $file): <?php $image->size($width, $height); // Return a new $image with the given dimensions (proportional, center crop) $image->width($width); // Return a new $image with the given width (proportional height, center crop) $image->height($height); // Return a new $image with the given height (proportional width, center crop) $image->getVariations(); // Returns a WireArray (Pageimages) of all size variations of this image. @advanced $image->removeVariations(); // Deletes all size variations of this image (be careful) @advanced1 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
-
This is great! Thanks for posting this. This is a great guide for people that want to implement some of PW's form controls outside of the admin template. It looks like you've got all the parts covered. Since this thread is turning into a helpful tutorial and reference, I want to cover the different ways of getting and setting values to Inputfields: <?php // setting $inputfield->attr('name', 'value'); $inputfield->set('name', 'value'); $inputfield->name = value; // same as set() above, but shorter // getting $value = $input->attr('name'); $value = $inputfield->get('value'); $value = $inputfield->value; // same as get() above, but shorter The attr() method is designed for explicitly setting setting/getting attributes that should go with the form input. For instance, 'name', 'class', 'id', 'value', 'checked', 'type', or whatever other attributes you want to go with the input. It should not be used for anything else because whatever you pass to it will end up as an attribute on the markup that gets output. Whereas the set(), get() and direct reference methods are designed for setting/getting other properties, like field configuration options. They also work with attributes like the attr() method, but it's better to use the attr() method when setting an attribute just to be clear to PW that you intend that to be an actual attribute with the markup that gets output. If you look in PW's code, you might also see it using these two functions in some instances: <?php $inputfield->setAttribute('name', 'value'); // same as $inputfield->attr('name', 'value'); $value = $inputfield->getAttribute('name'); // same as $value = $inputfield->attr('name'); These are the same thing as the attr() method, and the preferred syntax is to use the attr() method in your code. Internally, PW translates the attr() method to either setAttribute() or getAttribute(), depending on the number of arguments. The reason setAttribute() and getAttribute() exist is for people creating new Inputfield classes... it's easier to override single purpose methods rather than multi-purpose methods (like attr). But on a public interface, it's easier to use a multi-purpose method like attr(), so I recommend ignoring setAttribute() and getAttribute() unless you are developing new Inputfields. Variations of attr() In addition to getting and setting single attributes, the attr() method can also set multiple attributes at the same time. Below are all the possible variations (some repeated from above): <?php // set single attribute (same as example above) $inputfield->attr('name', 'value'); // get single attribute (same as example above) $value = $inputfield->attr('name'); // set multiple attributes with same value $inputfield->attr('id+name', 'value'); // set multiple attributes with different values $attrs = array( 'name' => 'value', 'name' => 'value', // etc.. ); $inputfield->attr($attrs); Inputfields that contain other Inputfields One type of Inputfield is the InputfieldWrapper, and it's designed solely to contain other Inputfields. Examples of InputfieldWrappers also include InputfieldForm and InputfieldFieldset (all are derived from InputfieldWrapper). On these Inputfields, the get() and direct reference can be used to retrieve any one of the fields by name: <?php $inputfield = $form->get('your_field_name'); $inputfield = $form->your_field_name; // direct reference works as alternate syntax Internally, the two calls above translate to this: <?php $inputfield = $form->find("name=your_field_name")->first(); What that means is it'll find any field in the form, not just direct children of the field you are checking. So a call to $form->get('your_field_name') will return the associated field, regardless of of many fieldsets it's wrapped under. This is just to keep things simple. After all, the form fields are all living in the same namespace when the form gets output. By the way, that find() method mentioned above can be used with any selector, just like with pages. It will return all inputfields in the form that match the properties you give it. But in practice, I've not ever needed it in my forms, so not sure how useful it really is. You can add/remove Inputfields as children using these methods. In the example below, we'll assume that $form is an instance of InputfieldForm: <?php $form->append($inputfield); // append an inputfield to the form $form->prepend($inputfield); // prepend an inputfield to the form $form->add($inputfield); // same as append() $form->remove($inputfield); // remove inputfield from the form Built in properties All Inputfields have these built-in properties that you can set or get: <?php $inputfield->label = "The clickable label that appears above this field. Should only be a few words."; $inputfield->description = "A longer description that appears below the label. Can be any length."; $inputfield->notes = "A extra highlighted area that appears under the field. Can be any length."; $inputfield->head = "Headline that appears below label/above description. "; // PW 2.1 only! $inputfield->id; // HTML 'id' attribute. Auto-generated if you don't set it. $inputfield->name; // HTML 'name' attribute, required $inputfield->value; // HTML 'value' attribute, if applicable $inputfield->class; // HTML 'class' attribute, optional $inputfield->required = 0; // value not required for this inputfield $inputfield->required = 1; // value IS required for this inputfield $inputfield->collapsed = Inputfield::collapsedNo; // Field will display open (this is the default) $inputfield->collapsed = Inputfield::collapsedYes; // Field will display collapsed, requiring a click to open $inputfield->collapsed = Inputfield::collapsedBlank; // Field will display collapsed only if blank $inputfield->collapsed = Inputfield::collapsedHidden; // Field will not be rendered in the form1 point
-
Hi Rith0s! Isn't there actually a video??? Anyway, I'll try to clarify a little here: 1. thing to know: one template in admin = one template file in /site/templates/. Whatever content is using this template, PW will try to parse contents of page through that php file. 2. template consists of PHP code to pre-process data and HTML output. HTML output (for convenience) can be also in external code called with require/include/flush or any other method, so you modify just one master template. 3. PW2 gives you few global variables to use in your template: $page (current page, it's fields [also in global $fields], and various (and some advanced too!) methods) $pages (connector to PW2 page tree) $input $session $sanitizer Full list with explanation here: http://processwire.com/api/variables/ More info about templates: http://processwire.com/api/templates/ Also, here is one of my templates with comments (hope it helps): <?php /* * Template: members.php * * Shows list of members based on date */ require_once '_inc/_functions.php'; //various functions if (!empty($page->body)){ //if we have $page->body (i.e. if field 'body' is filled) $o = new OutputArray('<h1>Heading 1</h1>'); //OutputArray is my own class. It's just an array to put strings into and then output on one place, //because it's faster than multiple $string .= 'addThis'; $o->add('<div class="tinymce">'.$page->body.'</div>'); }else{ $o = new OutputArray(); } $o->add('<h2>Heading 2</h2>'); $o->add('<ul class="clenovia">'); //here I get one page (by url) and then all of it's children (which is my members template, grouped in group 1) into $clenovia $clenovia = $pages->get('/s/clenovia-zboru/')->children('sort=sort'); $i = 0; foreach($clenovia as $c){ $foto = $c->foto->size(160,160); $o->add(s(CommonHTML::getPart('clen_zboru'), false, (++$i%3===1)?' class="cl"':'', $foto->url, $c->title, $c->uloha ));//here I ouput HTML for each of members of group 1 – s() is my shortened sprintf() function } $o->add('</ul>'); $o->add('<h2>Pravidelní spolupracovníci</h2>'); $o->add('<ul class="clenovia">'); //here I get another pageand then all of it's children (members, group 2) into $clenovia $clenovia = $pages->get('/s/pravidelni-spolupracovnici/')->children('sort=sort'); $i = 0; foreach($clenovia as $c){ $foto = $c->foto->size(160,160); $o->add(s(CommonHTML::getPart('clen_zboru'), false, (++$i%3===1)?' class="cl"':'', $foto->url, $c->title, $c->uloha )); // output HTML again } $o->add('</ul>'); /* * OUTPUT */ include("./head.inc"); // here I include $page headers – <head> section, <body> opening, navigation and everything BEFORE content // Not really necessary, but wanted the markup to line up with where it left off in header include, // so put four tabs before the bodycopy before outputting it: – I left here Ryan's template text. I am rebel! echo "\t\t\t\t".$o->render(); include("./sidebar.php"); //my sidebar custom code (which again works with $pages...) include("./foot.inc"); //end of content <div>, GA, </body> and that's all folks I tried to add as much comments as I can, although I'm not sure I made myself particulary clear But I sure hope it helps1 point