Leaderboard
Popular Content
Showing content with the highest reputation on 03/03/2013 in all areas
-
Captain Hook ProcessWire Hooks Cheatsheet http://somatonic.github.com/Captain-Hook/ or on processwire.com http://processwire.com/api/hooks/ I created a simple list with a live search for all hookable methods available in the core. All methods prefixed with a "___" (3 underscores) are hookable. Methods can be made hookable by simply adding those ___ to it. ------------------------- I usually don't really need this, but thought it would be good to have an official list for reference. I used Sublime Text2 for searching and dumb a file with a search for " ___" in wire core. From this list I created a html file with a php script and added some fuzzy live search, similar to the API cheatsheet. If you use Sublime Text 2 like me you can simple use Goto Anything command super+p to show a fuzzy search for files. Enter a class name you want to search for. For example "fields" or "process page edit" you will recieve a list of files found in PW. Highlight the file and typ a @ to see the symbol list quickly or select the file and super+r the get the symbol list.11 points
-
The answer is both Inputfields and Fieldtypes, but they are validating in totally different contexts. Inputfields validate user input. Fieldtypes validate data set to a $page, regardless of where it comes from. Think of Fieldtypes as API-side type validation, and Inputfields as interactive/user-input validation. Here's more detail: Inputfields only come into play when there's interactivity, i.e. a form and a user inputting something. Input should be validated by Inputfields so that the data is valid enough to echo back to the user, or for something else to pull the value from it. Inputfields should always be validated server-side where appropriate, but can also optionally include client-side validation. Inputfields can be used separately from Fieldtypes (they are used throughout ProcessWire in all forms). If there is some kind of input validation that isn't specific to a page or fieldtype, then it should be done by the Inputfield. Meaning, most validation responsibility goes with the Inputfield and an Inputfield shouldn't assume there's going to be any more validation beyond it. Inputfield sanitization/validation is done in $inputfield->processInput() or $inputfield->setAttribute('value', ...). The processInput() method is the first line of defense for values coming directly from a form. Whereas the setAttribute('value', ...) will see values sent from the form as well as values sent from the API to the $inputfield, like an $inputfield->attr('value', 'some value'), call. Where you put your sanitization/validation depends on what you are trying to account for. You may see some Inputfields have a setAttributeValue() function. This is not part of the Inputfield interface. It's just a methodology I sometimes use to isolate setAttribute('value', ...) for more readable code. Inputfields report errors by calling $this->error('error message'); The user will see that error message within the context of the field. Fieldtypes come into play every time a value is populated to a page. This could be from the API, the core, modules, importers, Inputfields… really anything. They need to validate that the value sent to the page is consistent with the type of data the Fieldtype is responsible for (type validation). So if the Fieldtype only stores a string, then it needs to make sure it's a string. If you set something invalid to a $page, the Fieldtype needs to either convert it to be something valid or if it can't, throw it out. For the most part, they should do it as quickly and silently as possible, because they get such a high volume of traffic. Not to mention, Fieldtypes can't assume there's a user present to see anything. Fieldtype sanitization/validation is performed by $fieldtype->sanitizeValue(). Every value set to a $page gets routed through that function, for the appropriate fieldtype. Whatever you do in there needs to be fast. That would be the correct behavior for the Fieldtype, but not for the Inputfield. The scope for Inputfields goes beyond just pages. They don't know what they are being used for. If they did, then their usefulness would be much less. But that's just "in general". There are some cases where you are building a Page-dependent Inputfield and your Inputfield needs to know about the $page being edited. Core examples would Inputfields related to files and repeaters. In that case, make your Fieldtype pass it along to the Inputfield. Each Fieldtype has a getInputfield() method that gets a copy of the $page and $field being edited. It has to return the appropriate Inputfield to edit the provided data. So you can easily send it along to the Inputfield right from there: public function getInputfield($page, $field) { $inputfield = wire('modules')->get('InputfieldSomething'); $inputfield->set('editPage', $page); // inputfield now has a $this->editPage property return $inputfield; } They can report error conditions, but technically they aren't the place for it. Yes. In general, Fieldtypes can't assume there's anyone there to see an error. But if you have some need where you think it is necessary to do from the Fieldtype, try $this->error('message') … it will only be seen in an interactive context. If you want to report an API error, throw an Exception. But if you can keep all of your error reporting in the Inputfield, that is the right place for it.3 points
-
Version 0.9.2 of this module (just pushed to GitHub) introduces support for multi-language fields. See commit details for more info. I've also brought in some minor fixes etc. during this weekend, so if you've installed this module you should consider updating.2 points
-
I know this is an old thread, but it was one of the first results when I searched for 'ProcessWire Object Cache'. I wanted to store a lot of objects in the cache, so I just converted the MarkupCache module to an ObjectCache module. Nothing fancy; it just adds (un)serialize to the get/save methods. But that alone saves me quite a but of time in this project and results in cleaner (less logic) templates. The code is available for free (and at your own risk ) at https://gist.github.com/jkenters/50190892 points
-
------------------------- Update November 2018: This language pack has now a new maintainer. Please see the new thread for updated versions and discussion. ------------------------- Well here's my first try to translate it to german ("de-de") All of the the translations are right but I'll change some later to sound nicer. And, I don't know if the nativ english speaking people here will understand it, but this translation uses "Sie" to address the user formally. (There's a difference between "du" (means you) and "Sie). But I guess "Sie" is the better choice. UPDATE: - Improved some translations to sound nicer. UPDATE 2: - added some new translations UPDATE 3: - added translations for new functions (like cloning) UPDATE 4: Please see this new thread from the new maintainer @jmartsch de-de (updated 1323468757).zip1 point
-
I launched it today: http://fyp.washington.edu/ I can't even begin to explain how excited I am by this software. It feels like I accomplished more in a month than in the last ten years of professional web dev work. Finally, a CMS geared to the needs of content publishing and information modeling (i.e. taxonomy and ontology) -- not news, widgets, or journaling. Like so many others I had been struggling with the Drupal/Wordpress dichotomy. Drupal feels like hitting myself in the head with a hammer and Wordpress is insecure and inflexible. And both their inner workings seem completely opaque, no matter how often I build with them. Enter PW, CMS of my dreams. The FYP site is combined with Zurb's Foundation Framework, which I am similarly enthusiastic about. Also above all jQuery + CSS3, which seem like a never-ending treasure chest of wonders. I did the interface design and development as well as the information architecture and all of the programming. My favorite thing about the site is the way I was able to give it gears that turn with the seasons -- for each season of the year I added tag "pages" and then tailored parts of the interface to match. The homepage image, the default header, and the selection of front page slides are all determined by what time of year it is. I was able to expose almost EVERYTHING to the content stakeholders through the flexible field system. I could totally get run over by a truck tomorrow and all would be well. I LIKE THIS. Maybe some don't. But I've always been in this field in the hopes of empowering people and making room for creativity. ProcessWire works with these goals, not against them. Cheers, Jenn p.s. the slider is RoyalSlider. I dig it too.1 point
-
We had a slight problem with ImageSizer recently; everything seemed to be fine but creating thumbnails still failed. The reason for this turned out to be that those images were of unsupported type (windows bitmaps) yet their extension was ".jpg" and thus ImageSizer considered them proper JPEG's and acted accordingly. Anyway, sorry for the spam but this is the solution I ended up implementing. I'd be grateful if Ryan (or someone else who knows the core well) would take a look and tell me if this is a valid solution -- and if it is, I'd like to suggest changing current extension-based "filtering" to something more like this I also took a look at the Upload class / InputfieldFile, but seems to me that implementing proper imagetype filtering there would require a lot of work.. and doesn't necessarily even make sense in that context. --- wire/core/ImageSizer.php (revision 1717) +++ wire/core/ImageSizer.php (working copy) @@ -46,6 +46,12 @@ ); + /** + * Type of image + * + */ + protected $imagetype; + /** * Allow images to be upscaled / enlarged? * */ @@ -67,11 +73,10 @@ * File extensions that are supported for resizing * */ - protected $supportedExtensions = array( - 'gif', - 'jpg', - 'jpeg', - 'png', + protected $supportedImagetypes = array( + IMAGETYPE_GIF, + IMAGETYPE_JPEG, + IMAGETYPE_PNG, ); /** @@ -83,9 +88,10 @@ $this->filename = $filename; $p = pathinfo($filename); $this->extension = strtolower($p['extension']); + $this->imagetype = exif_imagetype($filename); $basename = $p['basename']; - if(!in_array($this->extension, $this->supportedExtensions)) + if(!in_array($this->imagetype, $this->supportedImagetypes)) throw new WireException("$basename is an unsupported image type"); if(!$this->loadImageInfo()) @@ -130,12 +136,9 @@ $source = $this->filename; $dest = str_replace("." . $this->extension, "_tmp." . $this->extension, $source); - switch($this->extension) { - case 'gif': $image = @imagecreatefromgif($source); break; - case 'png': $image = @imagecreatefrompng($source); break; - case 'jpeg': - case 'jpg': $image = @imagecreatefromjpeg($source); break; - } + if($this->imagetype == IMAGETYPE_GIF) $image = @imagecreatefromgif($source); + if($this->imagetype == IMAGETYPE_PNG) $image = @imagecreatefrompng($source); + if($this->imagetype == IMAGETYPE_JPEG) $image = @imagecreatefromjpeg($source); if(!$image) return false; @@ -143,7 +146,7 @@ $thumb = imagecreatetruecolor($gdWidth, $gdHeight); - if($this->extension == 'png') { // Adam's PNG transparency fix + if($this->imagetype == IMAGETYPE_PNG) { // Adam's PNG transparency fix imagealphablending($thumb, false); imagesavealpha($thumb, true); } else { @@ -155,7 +158,7 @@ imagecopyresampled($thumb, $image, 0, 0, 0, 0, $gdWidth, $gdHeight, $this->image['width'], $this->image['height']); $thumb2 = imagecreatetruecolor($targetWidth, $targetHeight); - if($this->extension == 'png') { + if($this->imagetype == IMAGETYPE_PNG) { imagealphablending($thumb2, false); imagesavealpha($thumb2, true); } else { @@ -170,20 +173,13 @@ imagecopyresampled($thumb2, $thumb, 0, 0, $w1, $h1, $targetWidth, $targetHeight, $targetWidth, $targetHeight); // write to file - switch($this->extension) { - case 'gif': - imagegif($thumb2, $dest); - break; - case 'png': - // convert 1-100 (worst-best) scale to 0-9 (best-worst) scale for PNG - $quality = round(abs(($this->quality - 100) / 11.111111)); - imagepng($thumb2, $dest, $quality); - break; - case 'jpeg': - case 'jpg': - imagejpeg($thumb2, $dest, $this->quality); - break; + if($this->imagetype == IMAGETYPE_GIF) imagegif($thumb2, $dest); + if($this->imagetype == IMAGETYPE_PNG) { + // convert 1-100 (worst-best) scale to 0-9 (best-worst) scale for PNG + $quality = round(abs(($this->quality - 100) / 11.111111)); + imagepng($thumb2, $dest, $quality); } + if($this->imagetype == IMAGETYPE_JPEG) imagejpeg($thumb2, $dest, $this->quality); unlink($source); rename($dest, $source); ... and yes, that's output from SVN diff. I hope you guys can cope with that / understand what's going on in there. I'm not very familiar with Git and how it handles stuff like this. Sorry.1 point
-
You should copy/paste these explanations to the wiki - this is important stuff.1 point
-
Thanks for the explanation! Like I said it's a new world for me but storing metadata does seem to make sense -- at least for these "serious photographers" you've mentioned1 point
-
I'd really love to see swiftmailer integrated as an option for all emailing. I have used it exclusively since it was released in 2005 and it is just brilliant for everything from attachments to combined plain text / html versions of emails, through to bulk enewsletter mail outs to thousands of recipients, including Mail merge. It has various features to prevent overloading mail servers etc. A brilliant mailing class. I have already used it with PW, but would love to see it part of the core and directly accessible from the API.1 point
-
In short: every serious photographer tags his work in his workflow but at least the public files. For this, before 2004, there was only the IPTC-Standard. In 2004 Adobe starts to take this over in its own featured XMP-format. IPTC is now integrated in XMP as IPTC-core and IPTC-extended whereas the older IPTC-Marker can/will be used in parallel, - what has confused a lot of workflow setups. In PHP-world the common workaround was / is to strip out every metadata (XMP, EXIF, IPTC) and only writeback into the older IPTC-Marker. This way all further readers, incl. Adobe's, get same infos. This is right. As I've pointed to above, most of these standards are not of interest in serious image business. for me all Exifdata (without the copyright notice) is rubbish You have already pointed to the PHP-JPEG-Metadata-Toolkit what I would use for a 'big solution' whereas a small solution only needs internal PHP-functions. Combined solution could be: reading with Metadata Toolkit and writeback most important (merged) data only to IPTC-Marker. (reduces filesize, especially with small output length)1 point
-
Seems that you've only got 16 MB of memory reserved for PHP. That's awfully small amount and could definitely result in problems like this. Any chance that you could increase this? Similar problem was discussed here and in that case increasing memory limit was the solution. I would suggest something like 128 MB, but according to that thread even 30 MB should be enough1 point
-
Welcome to the forums! I think Wanze meant $config->debug = true; You could also try and delete module cache files (in case you've copied site/assets/cache as well): rm site/assets/cache/Modules.*1 point
-
You should be able to iterate through fields without knowing their names - the Cheatsheet should help you there. Something along the lines of get the page template, iterate through template->fields and then you have access to do something like $page->($field->name)->removeAll(); Just typing that quickly on my phone but hopefully you get the idea.1 point
-
Looks like that approach should work, at least when there aren't hundreds of private or draft articles. And that allows you to use sort and limit too in the last find(). Actually any other approach would work better in the long run than iterating over the complete list, I guess .1 point
-
No, unfortunately you can't. That's the "either-or selector" mentioned in roadmap for ProcessWire 2.5+ (Winter 2013/2014). Those examples from the documentation SiNNuT refers to do mention the or-operator, but it can't be used quite like this. "Or" is fine within a single selector but currently there's no support for having an "or" between two or more selectors, it's always "and" which is denoted by a "," (comma). On the other hand, if you don't need native pagination for the results of this kind of query (and there won't be too many results!), you could use something along these lines: $results = $pages->find('fieldA=xy'); $additionalResults = $pages->find('fieldA=z, fieldB=x'); // this leaves no duplicates to the PageArray $results->import($additionalResults); The resulting PageArray can be also sorted and sliced to get exactly what you need. But again, by now you've already fetched all the matching pages from the database into memory, so this is merely to tidy things up - or the core of a custom pagination of course. // sort first by fieldA ascending, then by fieldB descending and leave only 10 items starting from index 50 $slicedResults = $results->sort('fieldA, -fieldB')->slice(50, 10); So for small amount of data there's quite an easy way to get around it. But for larger amount of data you'd need to come up with another kind of method, probably one that depends on the nature of the data you're dealing with.1 point
-
I have created a sample module that does mapping two page fields against each others As per http://processwire.com/talk/topic/2384-change-the-value-of-one-field-by-editing-another-one-possible/ https://gist.github.com/somatonic/4335296 I also have a rough module that adds links to the pages linked after saving, but it's not something I can share. But looks like it's not what you actually ask for, but anyway all is possible.1 point
-
Thanks guys. I'm someone that likes to think a lot before I respond to questions, and didn't have time to do that here (it was a Skype interview rather than by email or something). But I'm happy with how it worked out. And perhaps the "live" nature makes for a more interesting interview. Very appreciative to Mike for inviting me to do this. I'm really liking the huge ProcessWire logo at cmscritic.com too.1 point
-
Good morning/evening/night or whatever! I just commited to Version 1.0.2. Here are the new Features: Permission Checking: Don't show pages that aren't editable by the current user. Also removed all actions that the user doesn't have permissions to execute. You can directly edit a single page over Fancybox by clicking the small "edit" link after a page (thanks raydale) Added Batch-Creating of Pages Batch-Creating Screenshot taken with Soma's great new Teflon theme Includes permission checking and Family template restrictions. This means in detail: The selected parent must accept children and their template The pages template must accept the parents template User needs the permission to add children to the selected parents template User needs the permission to create Pages for the chosen Template How does it work? 1) Select a parent where your new pages will be added as children 2) Add as many pages as you want by clicking "add Page" 3) Click "Create Pages" You must enter a title and choose a template. The name is optional: If left empty, Pw will generate this for you. Batch-creating tips The chosen template and the statuses are always cloned from the last row. So if you need to add 30 pages with the same template, define it first and the click "add Page" - i'll make your life easier ;-) You can drag & drop the table rows should you want to change the order. The draging looks ugly but it works. For the lazy dogs and keybord hackers among us, you can add a new row by pressing "ctrl+n". This works (at least in firefox) only if no input has focus. After adding a new row, the title input gets the focus. By pressing 3 times tab you arrive at the published-checkbox, here the short-cut works. Restrict Batcher for a user to only allow editing or creating Create permissions "batcher-edit" and/or "batcher-add". As soon those exists, the module checks if the current user has those permissions. Good night1 point
-
If you have a robots.txt, I would use it to specify what directories you want to exclude, not include. In a default ProcessWire installation, you do not need to have a robots.txt at all. It doesn't open up anything to crawlers that isn't public. You don't need to exclude your admin URL because the admin templates already have a robots meta tag telling them to go away. In fact, you usually wouldn't want to have your admin URL in a robots file because that would be revealing something about your site that you may not want people to know. The information in robots.txt IS public and accessible to all. So use a robots.txt only if you have specific things you need to exclude for one reason or another. And consider whether your security might benefit more from a robots <meta> tag in those places instead. As for telling crawlers what to include: just use a good link structure. So long as crawlers can traverse it, you are good. A sitemap.xml might help things along too in some cases, but it's not technically necessary. In most cases, I don't think it matters to the big picture. I don't use a sitemap.xml unless a client specifically asks for it. It's never made any difference one way or the other. Though others may have a different experience.1 point
-
Hi Aren I haven't used EE so I can't help you "translate" However, I will just deal with the slideshow for the moment. I will assume that the slideshow is just an image for the moment. You can do this with just one field - create a new field using the Images type. Call it slide_images (or anything) You can set that field to upload as many images as you like. It also comes with a description field which you can use for a basic caption. Add it to a template. The images field will return an array of the images. So, in the template file do: <?php foreach($page->slide_images as $image) { ?> <img src="<?php echo $image->url; ?>" /> <p><?php echo $image->description; ?></p> <?php } ?> That will return all your images - all you need to do is to make that work with your favourite slider! If you want a much more complicated system, you can use "repeater" fields, which is a way of grouping fields together and repeating them in the form, and also the Thumbnails module, which is an alternative image field (crop-image) that allows you to create whatever thumbnails you want while uploading image. http://modules.processwire.com/modules/fieldtype-crop-image/ http://modules.processwire.com/modules/fieldtype-repeater/ Joss1 point
-
1 point
-
Hi antknight That wouldn't work - like I wrote that would produce an error 500. However, I found the cause of the problem in the .htaccess file: #Options +FollowSymLinks Once I commented out this directive, the problem disappeared. I found the solution here: http://www.wallpaper...pache-t718.html And a general explanation of the directive here: http://www.webmaster...orum11/1962.htm I hope this helps others with the same problem. /Allan1 point
-
Teppo, the dev branch now now has switched from extension detection to type detection per your suggestion and code. https://github.com/ryancramerdesign/ProcessWire/blob/dev/wire/core/ImageSizer.php Thanks, Ryan1 point
-
I had some time at hand and nothing else to do, so I went ahead and translated some more. All 70 language files translateable as of PW 2.2.2, to be exact. Someone please double-check these. I'm sure they're far from perfect, and I'll gladly accept any suggestions for better translations or hints to typos. I'll also continue to refine some of the translations, but after this little bulk translation marathon, I need a break. I also put them in a GitHub repo: https://github.com/y...wled/pw-lang-de1 point
-
Just wanted to add a couple more notes to this: Using a 'summary' field I think it's more common on this type of page that you would display a summary of the news story rather than the whole news story... and then link to the full news story. To display a summary, you could have a separate 'summary' field in your template, which would be just a regular textarea field where you would have a 1-2 sentence summary of the article. And you would display this 'summary' field rather than 'body' field in the news_index template. If you wanted to autogenerate a summary from the 'body' field (rather than creating a new 'summary' field), you could just grab the first sentence or paragraph of the body and use that as your summary. This is how I usually do something like that: <?php // make our own summary from the beginning of the body copy // grab the first 255 characters $summary = substr($story->body, 0, 255); // truncate it to the last period if possible if(($pos = strrpos($summary, ".")) !== false) { $summary = substr($summary, 0, $pos); } That's a really simple example, and you may want to go further to make sure you are really at the end of a sentence and not at an abbreviation like "Mr." In the example that Moondawgy posted, it makes sense to autogenerate a summary (if he needed it). But in other cases, the 'body' can be quite long (and take up a lot of memory), and it makes more sense to maintain a separate summary field if you have to keep a lot of pages loaded at once. This is really only an issue once you get into hundreds of pages loaded at a time. It's not an issue in these examples, but I just wanted to point it out. Autojoin Using the 'autojoin' optimization can increase performance on fields that get used a lot. Not using it can reduce the page's memory footprint. What is more desirable in each instance depends on your situation. In this news section example, the date and body fields would benefit from having 'autojoin' turned ON. See this page for an explanation: http://processwire.com/talk/index.php/topic,32.0.html1 point
-
It looks like your news page example displays 4 stories per page, and it displays the full bodycopy for each of them. Assuming the same structure and fields of the pages you posted, you'll need to create two templates: 1. news_index.php 2. news_story.php You can call those templates above whatever you want, but just note that we'll use a separate template for news stories and news items. Your news_story template will contain the following fields: 1. title 2. date (date) 3. body (textarea) And it's markup might look like this (excluding headers, footers, etc.): /site/templates/news_story.php: <h1><?=$page->title?></h1> <div id='bodycopy'> <?=$page->body?> </div> Not much action there. Your news_index is where most of the action will happen. In Admin > Setup > Templates > news_index > Advanced, check the box for "Page Numbers" to turn them on. Save. Here is what the code in your news_index.php might look like: /site/templates/news_index.php: <h1><?=$page->title?></h1> <?php // start the news stories list echo "<ul>"; // get the stories for this page $stories = $page->children("limit=4, sort=-date"); // note if you set the stories to sort by date descending on the /news/ page // in the admin, then you can omit the "sort=-date" above. // cycle through each story and print it in a <li> foreach($stories as $story) { echo " <li><a href='{$story->url}'>{$story->title}</a> <p><strong>Date:</strong> {$story->date}</p> {$story->body} </li> "; } echo "</ul>"; // get values for our placemarker headline $start = $stories->getStart(); $end = $start + count($stories); $total = $stories->getTotal(); $num = $input->pageNum; $lastNum = ceil($total / $stories->getLimit()); // output the placemarker headline echo "<h4>Showing $start - $end of $total Article/s | Page $num of $lastNum</h4>"; // output pagination links echo $stories->renderPager(); Lets say that you don't want the pagination links that renderPager produces, you can always modify it's output by passing params to it. See the page about pagination here: http://processwire.com/api/modules/markup-pager-nav/ But if you want your literal "previous" and "next" buttons like on your site, then you'll want to insert your own logic to do that. Something like the next example. Note I'm reusing the vars I set in the previous example here for brevity. This snippet would replace the renderPager() method in the previous example. <?php // make the previous link if($num > 2) $prevLink = "./page" . ($num-1); else if($num == 2) $hrefLink = "./"; // page 1 else $prevLink = "./page" . $lastNum; // last page // make the next link if($num >= $lastNum) $nextLink = "./"; // page 1 else $nextLink = "./page" . ($num+1); // output the prev/next links: echo "<p><a href='$prevLink'>Previous</a> <a href='{$nextLink}'>Next</a></p>"; Disclaimer: the examples on this page are just written off the top of my head and are not actually tested examples. You'll likely have to tweak them. In particular, you may have to add or subtract 1 in a few places to get the right numbers. If you end up adapting this, please let me know of any errors I have here so that I can correct them.1 point