Leaderboard
Popular Content
Showing content with the highest reputation on 01/18/2016 in all areas
-
On my side i prepared a function for srcset and <picture> tag creation. Function output look like : <picture> <!--[if IE 9]> <video style='display: none;'> <![endif]--> <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.404x270.jpg' media='(max-width: 479px)' /> <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.692x462.jpg' media='(max-width: 767px)' /> <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.427x285.jpg' media='(max-width: 959px)' /> <!--[if IE 9]> </video> <![endif]--> <img src='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.630x421.jpg' alt='terra-nova-001' class="lazyload uk-width-1-1" /> </picture> Here are my functions : /** /** * Generate Attributes Array or String * * @param $item * @return string */ function buildAttrs($item) { $attributes = ""; // echo "<pre>Key : " . print_r($item, true) . "</pre>"; if(array_key_exists('attributes', $item) && is_array($item['attributes'])) { foreach($item['attributes'] as $key => $attr) { $attributes .= ' ' . $key . '="' . $attr . '"'; } } return $attributes; } /** * * @param $image * @param $key * @param $options * @return string */ function buildSrcAndSrcset($image, $key, $options) { $return = ''; // echo "<pre>Key : {$key}, " . print_r($options, true) . "</pre>"; if(!empty($options[$key]) && !empty($options[$key]['sets']) && is_array($options[$key]['sets'])) { $x=1; $countSets = count($options[$key]['sets']); $sets = ""; foreach($options[$key]['sets'] as $k => $rules) { $y=$x++; $separator = ($y != $countSets) ? ", " : ""; if(!is_array($rules) && $rules == 'original') { $static_url = static_url($image->url); $sets .= "{$static_url} {$key}w{$separator}"; } elseif(isset($rules['width']) || isset($rules['height'])) { $size = imageResize($image, $rules); if(!is_null($size)) { $sets .= "{$size['url']} {$size['width']}w{$separator}"; } } } if($sets != "") $return = " {$key}='{$sets}'"; } elseif(!empty($options[$key]) && !empty($options[$key]['method']) && is_array($options[$key]['method'])) { $img = imageResize($image, $options[$key]['method']); if(!is_null($img)) $return = " {$key}='{$img['url']}'"; } elseif(!empty($options[$key]) && is_string($options[$key])) { $return = " {$key}='{$options[$key]}'"; } return $return; } /** * Image : Create <img /> tag with attributes and responsive lazyload option * * @param $image * @param array $options * @return string */ function image($image, $options = array(), $lightbox=FALSE) { $return = ""; // Alt attribute $alt = ($image->description != '') ? $image->description : pathinfo($image->filename, PATHINFO_FILENAME); $alt = " alt='{$alt}'"; if(array_key_exists('picture', $options) && is_array($options['picture'])) { $picture = $options['picture']; // Set Attributes $attributes = ""; if(array_key_exists('attributes', $picture)) { $attributes = buildAttributes($picture['attributes']); } $return .= "\n<picture{$attributes}>"; if(array_key_exists('source', $options['picture']) && is_array($options['picture']['source'])) { $return .= "\n\t<!--[if IE 9]><video style='display: none;'><![endif]-->"; $sources = $options['picture']['source']; foreach($sources as $key => $source) { $attrSrc = buildSrcAndSrcset($image, 'src', $source); $attrSrcset = buildSrcAndSrcset($image, 'srcset', $source); $attrDataSrcset = buildSrcAndSrcset($image, 'data-srcset', $source); $attributes = buildAttrs($source); $attrMedia = " media='{$key}'"; $return .= "\n\t\t<source{$attrSrc}{$attrSrcset}{$attrDataSrcset}{$attributes}{$attrMedia} />"; } $return .= "\n\t<!--[if IE 9]></video><![endif]-->"; } if(array_key_exists('img', $options['picture']) && is_array($options['picture']['img'])) { $img = $options['picture']['img']; $attrSrc = buildSrcAndSrcset($image, 'src', $img); $attrSrcset = buildSrcAndSrcset($image, 'srcset', $img); $attrDataSrcset = buildSrcAndSrcset($image, 'data-srcset', $img); $attributes = buildAttrs($img); $return .= "\n\t<img{$attrSrc}{$attrSrcset}{$attrDataSrcset}{$alt}{$attributes} />"; } $return .= "\n</picture>"; } elseif(array_key_exists('img', $options) && is_array($options['img'])) { $img = $options['img']; $attrSrc = buildSrcAndSrcset($image, 'src', $img); $attrSrcset = buildSrcAndSrcset($image, 'srcset', $img); $attrDataSrcset = buildSrcAndSrcset($image, 'data-srcset', $img); $attributes = buildAttrs($img); $return .= "\n<img{$attrSrc}{$attrSrcset}{$attrDataSrcset}{$alt}{$attributes} />"; } else { $src = " src='" . static_url($image->url) . "'"; $width = " width='{$image->width}'"; $height = " height='{$image->height}'"; // Set Attributes $attributes = ""; if(array_key_exists('attributes', $options)) { $attributes = buildAttributes($options['attributes']); } $return .= "\n<img{$src}{$width}{$height}{$alt}{$attributes} />"; } if(isset($lightbox) && $lightbox != FALSE) { $page = wire('page'); $title = ($image->description != "") ? $image->description : $page->title; $overlayEffect = (!is_bool($lightbox) && $lightbox != '') ? " " . $lightbox : " uk-overlay-fade"; $return = "\n<figure class='uk-overlay uk-overlay-hover'> \n\t{$return} \n\t<div class='uk-overlay-panel uk-overlay-background{$overlayEffect}'></div> \n\t<div class='uk-overlay-panel uk-overlay-icon{$overlayEffect}'></div> \n\t<a class='uk-position-cover' href='{$image->url}' title='{$title}' data-uk-lightbox=\"{group:'{$page->name}'}\"><span class='uk-hidden'>{$title}</span></a> \n</figure>"; } return $return; } /** * Resize Image * * @param $image * @param array $method * @return array|null */ function imageResize($image, $method=array()) { $alt = ($image->description != '') ? $image->description : pathinfo($image->filename, PATHINFO_FILENAME); if(isset($method['type']) && isset($method['width']) || isset($method['height'])) { // Set Resize Options if(isset($method['options'])) $options = $method['options']; else $options = wire('config')->imageSizerOptions; if($method['type'] === 'size' && isset($method['width']) && isset($method['height'])) { $size = $image->size($method['width'], $method['height'], $options); } elseif($method['type'] === 'width' && isset($method['width'])) { $size = $image->width($method['width'], $options); } elseif($method['type'] === 'height' && isset($method['height'])) { $size = $image->height($method['height'], $options); } else { $size = null; } if(!is_null($size)) { return array( 'url' => static_url($size->url), 'width' => $size->width, 'height' => $size->height, 'alt' => $alt ); } } elseif(is_null($method)) { return array( 'url' => static_url($image->url), 'width' => $image->width, 'height' => $image->height, 'alt' => $alt ); } return null; } /** * Return url with static url * * @param string $url * @return string */ function static_url($url="") { $config = wire('config'); if($config->debug === false && isset($config->static_url) && $config->static_url != "") { $static_url = $config->static_url; } else { $static_url = ""; } return $static_url . $url; } I set responsive sizes on my config file : /** * Responsive Image Options */ $responsiveSizes = array( 'small' => '480', 'medium' => '768', 'large' => '960', 'xlarge' => '1220' ); $config->resSmall = "(max-width: " . ($responsiveSizes['small']-1) . "px)"; $config->resMedium = "(max-width: " . ($responsiveSizes['medium']-1) . "px)"; $config->resLarge = "(max-width: " . ($responsiveSizes['large']-1) . "px)"; $config->resXlarge = "(min-width: {$responsiveSizes['xlarge']}px)"; And I created a file (including this file inside my init.php file) that file have responsive image sizes like : /** * Template --Villa List-- */ $respImgOptions['villa']['list'] = array( 'picture' => array( 'source' => array( $config->resSmall => array( 'srcset' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==', 'data-srcset' => array( 'method' => array( 'type' => 'size', 'width' => 404, 'height' => 270 ) ) ), $config->resMedium => array( 'srcset' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==', 'data-srcset' => array( 'method' => array( 'type' => 'size', 'width' => 692, 'height' => 462 ) ) ), $config->resLarge => array( 'srcset' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==', 'data-srcset' => array( 'method' => array( 'type' => 'size', 'width' => 427, 'height' => 285 ) ) ) ), 'img' => array( 'src' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==', 'attributes' => array( 'class' => 'lazyload uk-width-1-1' ), 'data-srcset' => array( 'method' => array( 'type' => 'size', 'width' => 630, 'height' => 421 ) ) ) ) ); And after all done calling images from page like : // on here you need to send single PageImage ! $img = image($page->image->first(), $config->respImgOptions['villa']['list']); Like this usage if you have https://github.com/aFarkas/lazysizes and https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/respimg every thing will work well !7 points
-
Processwire playing Aces in cms land I just noticed that with version 8 Drupal is waking up to decoupled. http://buytaert.net/the-future-of-decoupled-drupal Processwire has been playing it's decoupled front-end Ace since day 1. My opinion is that Processwire has a second decoupled Ace to play that needs more campaign: "everything is a page" To illustrate better what I mean is that my impression is that many processwire beginners pick up it's api and the decoupled front-end way of working but not the potential of "everything is page". An easy explanation for this is of course that many still associate a page with a webpage this established habit simply hinders to pick up the "everything is a page" potential of processwire. I have come across many examples of the "everything is a page" in the forum, here are two I could still recall, but there are many more amazing examples to find: 1. Multiple content areas with pages https://processwire.com/talk/topic/4487-homepage-with-multiple-content-areas/#entry44125 2. Making menus with pages https://processwire.com/talk/topic/11748-menu-building/#entry109226 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - In the Processwire about page (middle of the page) a general reference is made to "everything is a page" http://processwire.com/about/what/ But this general reference never made me pick it up until lately, and I am sure I am not the only one. The more I start working with this concept, the more I find it underestimated as a playing Ace for Processwire in cms land. We should collect all examples in the forum and select the best ones as a source for writing a new special article about the "everything is a page" and how to use it's potential in making your websites with processwire.4 points
-
Update: So I've been using Pete's dashboard module instead of the technique described above; it's quicker to setup, and easier to clone to other installs, and no need to have code in various places like the themes folder and in ready.php The hope/plan is to turn it into a full widget enabled dashboard module that i can install on various installations a) without having to do any hardcoding b) enable control over which widgets are shown on the dashboard (by user/role/permission) c) allow for easy configuration of colors, icons, columns, etc. To achieve this I setup some templates for different widget types, one is a shortcuts widget, another is a page lister widget; these each have pages and fields to configure them; i can set them to appear by user/role. in the future i can add different types of widgets as needed and then include them in the needed user's dashboard. This is using a combination of a free (MIT licensed) admin theme for bootstrap, but instead of using bootstrap as the css layout, it uses a tiny grid called rwdgrid which i s 2KB; it uses the box, and other widget classes from the admin theme.4 points
-
I actually think “page” is a stroke of genius. It keeps the learning curve low for beginners by giving them a word they can immediately understand and work with. You can either keep working under the assumption that a page represents an HTML document, or dig deeper little by little. You’ll install a module like Language Support, and notice that – what do you know – languages are pages, until you arrive at “everything is a page”.3 points
-
Thats true... as it should. when using: if ($childpages) you ask: If PageArray... which is always true. You should check if it contains pages with count for example. if (!count($childpages)) { // The pageArray doesn't contain pages // If not count pages, thus 0 } if (count($childpages)) { // yay we have at least 1 page } // or if ($childpages->count()) { // yay we have at least 1 page }3 points
-
Update: Version 0.1.2 Fixed bug whereby 'new tab' setting for new custom menu items would not work reliably In addition to the existing AsmSelect and Page Autocomplete options of adding pages to menus, you can now also use a PageListSelectMultiple. This is similar to the original version of MenuBuilder (not in styling but function ). Personally, I am not a fan* of the option....the tree jumps all over the place and can be unwieldy. Anyway, the feature is there for those who prefer it . Logged in as a Supersuser you will see the whole tree, of course. Not other users though. So, no 'danger'(?) of them adding admin pages to the menu! *I might rethink this and remove PageListSelectMultiple as an option..3 points
-
New in version 3.0 Removes the limitations of the previous releases! Now compatible with all Inputfield types including Select, SelectMultiple, Checkboxes, Radios, AsmSelect, PageListSelect, PageListSelectMultiple, and PageAutocomplete. When using the create new page feature, new pages are added to the field and selected automatically as soon as the modal is closed. No further input is required from the user. The "View" and "+ New" strings are now translatable The add new page links may be enabled independent of the view/edit links Code performance improvements GitHub: https://github.com/thetuningspoon/AdminPageFieldEditLinks Direct Download: https://github.com/thetuningspoon/AdminPageFieldEditLinks/archive/master.zip I ended up using a combination of different methods for populating the field with the new page once it's created. Some of the input types were fairly easy and could be updated without reloading the field, while others required some pretty wild code acrobatics, taking advantage of Ryan's new AJAX reload and repopulating the input with pages that were already selected but not yet saved. Please let me know if you run into any bugs. This was built mainly in Chrome with limited testing outside of it so far, so I expect some issues. I hope you guys enjoy the new features! Let me know if you have other suggestions for further enhancements.3 points
-
The Comment Class is not a module. It is a PHP file. You would have to require/include it first in your module, e.g. init() or earlier before you can call on it2 points
-
@dragan, I think this is the same issue that you were seeing with ProFields (per your topic there). I think PW is having trouble understanding your paths, potentially due to the spaces present in the path names and/or something to do with your Windows environment. I've not seen any other instances of this particular issue, but I'm going to be taking a closer look at the files you sent me and hopefully we can track it down. Hopefully we can resolve it with an adjustment to FileCompiler, but I've just not been able to identify what we need to adjust yet. @tpr It's funny you should mention that because the support is already built in. I didn't document it yet because I wasn't sure I was going to keep it there. But sounds like maybe we should keep it there. The format it uses is this: field.template.php example: body.basic-page.php Since this is already built in, you can try it out now if you'd like. It checks for a template-specific file before a general purpose one. It will use the template-specific one if present, or the general purpose one if not.2 points
-
sorry also i updated my first reply /** * Generate Attributes Array or String * * @param $item * @return string */ function buildAttrs($item) { $attributes = ""; // echo "<pre>Key : " . print_r($item, true) . "</pre>"; if(array_key_exists('attributes', $item) && is_array($item['attributes'])) { foreach($item['attributes'] as $key => $attr) { $attributes .= ' ' . $key . '="' . $attr . '"'; } } return $attributes; } /** * * @param $image * @param $key * @param $options * @return string */ function buildSrcAndSrcset($image, $key, $options) { $return = ''; // echo "<pre>Key : {$key}, " . print_r($options, true) . "</pre>"; if(!empty($options[$key]) && !empty($options[$key]['sets']) && is_array($options[$key]['sets'])) { $x=1; $countSets = count($options[$key]['sets']); $sets = ""; foreach($options[$key]['sets'] as $k => $rules) { $y=$x++; $separator = ($y != $countSets) ? ", " : ""; if(!is_array($rules) && $rules == 'original') { $static_url = static_url($image->url); $sets .= "{$static_url} {$key}w{$separator}"; } elseif(isset($rules['width']) || isset($rules['height'])) { $size = imageResize($image, $rules); if(!is_null($size)) { $sets .= "{$size['url']} {$size['width']}w{$separator}"; } } } if($sets != "") $return = " {$key}='{$sets}'"; } elseif(!empty($options[$key]) && !empty($options[$key]['method']) && is_array($options[$key]['method'])) { $img = imageResize($image, $options[$key]['method']); if(!is_null($img)) $return = " {$key}='{$img['url']}'"; } elseif(!empty($options[$key]) && is_string($options[$key])) { $return = " {$key}='{$options[$key]}'"; } return $return; }2 points
-
Thank you! Unfortunately this module doesn't use any ProcessWire fields (except for the images). It works only with HTML, therefore at this point building multilanguage sliders is nearly impossible. The only way you could build multilanguage sliders would be creating each time a new slider. However if you have access to your database you can easily use a little trick to speed up the process: add a new row in the slider table for each one of your languages. For example if you have German and English you can add two new rows (let's call them slider_de and slider_en) and you can copy and paste the code column to have the same settings as the original slider. Now you can translate your text in the administration section. As the last step you have to change the type of the Slider field from Slider to TextLanguage. In this way you can reference a different slider for each language, but remember that you have to type in the ID of the slider and not the name.2 points
-
Not with Likes but with Follows you can use the IPboard filter: ------------------ Another approach: Something like Kongondo uses, (Browserbookmarks with SearchCapabilities), but browser independent, could be: to use the bowsers functionality to send pagelinks by email. (It opens your default email program with a new email where the subject and body part is populated with the page title and page url). Before sending, you can add as many notices, text / tags / keywords / categories, or some copy / pasted segments from the webpage, etc. When sending this to a dedicated emailaddress that gets parsed by a module within PW, you have a browser independent storage with fulltext search.2 points
-
PrevNextTabs Module Github: https://github.com/outflux3/PrevNextTabs Processwire helper modules for adding page navigation within the editor. Overview This is a very simple module that adds Previous and Next links inline with the tabs on the page editor. Hovering over the tab shows the title of the previous or next page (using the admin's built in jqueryUI tooltips.) Usage This module is typically used during development where you or your editors need to traverse through pages for the purpose of proofing, flagging and/or commenting. Rather than returning to the page tree or lister, they can navigate with these links. Warnings If you are using PW version 2.6.1 or later, the system will prevent you from leaving the page if you have unsaved edits. For earlier versions, to avoid accidentally losing changes made to a page that might occur if a user accidentally clicks on one of these, make sure to have the Form Save Reminder module installed. http://modules.processwire.com/modules/prev-next-tabs/1 point
-
This basic tutorial is primarily aimed at those new to PW. It could also serve as a reference to others more seasoned PW users. The question about how to categorise content comes up in the forums now and again. Hopefully with this post we’ll have a reference to guide us right here in the tutorials board. Many times we need to organise our site content into various categories in order to make better sense of the data or to logically and easily access it. So, how do you organise your data when you need to use categories? Here are a few tips gathered from the PW forums on how to go about this. Using these tips will, hopefully, help you avoid repeating yourself in your code and site content and keep things simple. See the links at the end of this post to some useful discussion around the topic of categorisation. Before making decisions about how to organise your site, you need to consider at least three questions: What items on my site are the main items of interest? These could be people or things (cars, plants, etc.). In most cases, these are the most important content on which all the other stuff point to. Where do items need to be grouped into categories? This is about where items need to “live”. It is about the attributes of the items of interest (e.g. responsibilities, job types, colour, etc.). Attributes can have sub-attributes (e.g. a category job type = driver could be further sub-classified as job type role = train driver). Can they live in more than one place? - This is about having multiple attributes. There could be other issues such as the type of content your main items of interest are but that’s for another post. We’ll keep these examples simple. The main principles explained below still apply. There are at least three possible ways in which you can organise your content depending on your answers to the above three questions. These are: Single category Simple multiple categories Complex multiple categories These are illustrated below. Note that this is what I call them; these are not PW terms. 1. Single Category Suppose you need to do a site for a company that’s made up of several Departments each with employees performing unique functions. These could include “Finance”; “Media Communications”; “Administration”; “Technicians”; “Human Resources”; “Logistics”. We ask ourselves the following questions based on our 3 questions above: 1. Q: What items on my site are the main items of interest? A: Employees. 2. Q: What attributes of our items of interests are we interested in? A: Departments. (Single main category) 3. Do the Departments have sub-categories? A: Yes. (Multiple sub-categories) 4.Can Employees belong to multiple sub-categories? A: No. (Single sub-category) We conclude that what we need is a Single Category model. Why? This is because, in Single Categories model, items of interest can only belong to 1 and only 1 main/parent category and within that only 1 sub-category Employees in this company can only belong to one and only one department. Finance guys do their finance and Logistics guys do their stuff. Letting Techies do press conferences is probably not going to work; that we leave to the Media guys . Assuming the company has the following employees - James, John, Mary, Ahmed, Peter, Jason, Barbara etc., arranging our site content to fit this model could look like the following: Items of interest = Employees Categories = Departments Adopting out strategy to keep it simple and logical, let us write down, hierarchically, our employee names against their departments to mimic the PW tree like this: James Finance John Finance Mary Technician Ahmed Logistics Barbara Media Etc. We notice, of course, that departments start repeating. It doesn't look like we are doing this very logically. If we think about this carefully, we will conclude that, naturally, the thing (attribute in this case) that keeps repeating should be the main criteria for our categorisation. This may seem obvious, but it is worth pointing out. Also, remember, that as per the responses to our questions, the categories (Finance, Logistics, etc.) do not have sub-categories. In this aspect, we are OK. Using this principle about repeating attributes, we find that Departments, rather than Employees, need to be the main categories. Hence, we categorise our PW site content by doing the following. Create a template for each Department. Hence, we have a template called Finance, Logistics, etc. Add the fields needed to those templates. This could be a text field for holding Employee phone numbers, email field for email, title field for their names, etc. Create top level pages for each Department and assign to them their respective templates. Give them appropriate titles, e.g., Finance, Media, etc. Create a page for each employee as a child page of the Department which they belong to. Give them appropriate titles, e.g. James, John, etc. We end up with a tree that looks like this: 1. Finance (ex. main category) a. James (ex. item of interest) b. John c. Shah d. Anne 2. Logistics (ex. main category) a. Ahmed b. Matthew c. Robert d. Cynthia 3. Media a. Barbara b. Jason c. Danita 4. Human Resources a. Michael b. Pedro c. Sally 5. Technician a. Mary b. Oswald c. Dmitri d. Osiris Since an employee can only belong to one Department, our work here is done. We can then use PW variables, e.g. $page->find, $pages->find with the appropriate selectors to find employees within a Department. This is a very basic example, of course, but you get the idea. You have the choice of creating one template file for each category template as well. I prefer the method of using one main template file (see this thread). You could do that and have all Departments use different templates but a single template file. In the template file you can include code to pull in, for example, the file “technician.inc” to display the relevant content when pages using the template “Technician” are viewed. Example code to access and show content in Single Categories model $hr = $pages->find("template=human-resources, limit 50"); foreach ($hr as $h) { echo "{$h->title}"; } But sites do not always lend themselves to this model. Many times, items of interest will need to belong to multiple categories. 2. Simple Multiple Categories Let’s say you were building a site for cars - red cars, blue cars, 2-seaters, 5-seaters, etc. Again, we ask ourselves our questions based on our initial three questions: 1. Q: What items on my site are the main items of interest? A: Cars. 2. Q: What attributes of our items of interests are we interested in? A: Colour, Number of seats, Models, Year of manufacture, Types. (Multiple categories) 3. Do these multiple attributes have sub-attributes? A: Yes. e.g., the attribute Colour has several sub-categories - red, white, green, etc. (Multiple sub-categories) 4. Can Cars have multiple sub-attributes? A: No. e.g., a yellow car cannot be a green car. (Single sub-categories) We therefore conclude that what we need is a Simple Multiple Category model. Why? This is because, in Simple Multiple Categories, items of interest can belong to multiple parent categories. However, within those parent categories, they can only belong to one sub-category. Assuming we have the following cars, manufactured between 2005 and 2008, as items of interest: Mercedes, Volvo, Ford, Subaru, Toyota, Nissan, Peugeot, Renault, Mazda, arranging our site content to fit this model could look like the following: Items of interest = Cars Categories = Model, Year, Colour, Number of seats, Type Sub Categories = Model [Prius, etc.]; Year [2005, 2006, 2007, 2008]; Colour [Red, Silver, Black, White, Green]; Number of seats [2, 5, 7]; Types [sports, SUV, MPV]. Adopting out strategy to keep it simple and logical, if we wrote down our cars names against their attributes like this: Mercedes Model-Name: Year: 2005 Colour: Silver Seats: 2-seater Type: Sports Volvo Model-Name: Year: 2007 Colour: Green Seats: 5-seater Type: SUV Ford Model-Name: Year: 2007 Colour: Red Seats: 7-seater Type: MPV Etc We notice, again, that car attributes start repeating. In order not to repeat ourselves, we want to avoid the situation where our child pages “names” keep repeating. For instance, in the above example tree, we want to avoid repeating year, colour, etc. within the tree. Of course in the frontend our output needs to look like the above where we can list our cars and their respective attributes. We just don’t need a tree that looks like this in the backend. Since we have multiple categories and sub-categories, we need to rethink our strategy for categorising our content as illustrated below. The strategy we used in the first category model will not work well here. Hence, these repeating attributes (year, colour, etc.) need to be the main criteria for our categorisation. We need to end up with a tree that looks like this: 1. Cars a. Mercedes (ex. item of interest) b. Volvo c. Ford d. Subaru e. Toyota f. Range Rover g. Peugeot h. Renault i. Mazda 2. Model (ex. main category) a. Fiesta (ex. sub-category) b. Miata c. Impreza d. Matrix e. Prius f. E-Class g. XC-90 h. Scenic i. L322 j. 505 3. Year a. 2005 b. 2006 c. 2007 (ex. sub-category) d. 2008 4. Colour a. Red b. Silver c. Black d. White e. Green 5. Number of Seats a. 2 b. 5 c. 7 6. Type a. MPV b. Sports c. SUV d. Other At the top of the tree, we have our main items of interest, Cars. They do not have to come first on top of the tree like that but it just makes sense to have them like this. Next, we have the Cars’ categories (attributes). The main categories are parent pages. Each main category has children which act as its sub-categories (cars’ sub-attributes). For instance, the main category colour has sub-categories “red”, “green”, etc. Grouping them under their main category like this makes better sense than having them dangling all over the tree as parent pages themselves. Now that we know what we want to achieve, the next question is how do we go about relating our categories and sub-categories to our main items of interest, i.e., cars? Fields come to mind. OK, yes, but what about the sub-categories (2006, red, 5-seater, etc.)? Surely, we can’t keep typing those in text fields! Of course not; this is PW. We like to simplify tasks as much as we can. What we need is a special type of field. Page Reference Fields or Page Fieldtypes add the ability to reference other pages, either single or multiple pages, within a page. For instance, we could have a Page Reference Field in the template that our Car pages use. Let’s call this “car-template”. When viewing Car pages, we would have the ability to select other pages on our site that we wish to reference, for instance, because they are related to the page we are viewing. In other cases, we could also wish to reference other pages that contain attributes/values of the page we are viewing. This is the situation with our Cars example above. Hence, the sub-categories/sub-attributes for our Cars will be pulled into our car pages using Page Reference Fields. There are two types of Page Reference Fields; single page and multiple pages. What each do is obvious from their names. Single Page Reference Fields will only reference one page at a time. Multiple Page Reference Fields will reference multiple pages. OK, let’s go back to the issue at hand. We need to categorise Cars by various attributes. Do we need to reference the main categories (Year, Type, etc.) in our Car pages? In fact, we don’t. What we need to reference are the sub-categories, i.e. 2005, red, SUV, etc. These will provide the actual attributes regarding the parent attribute of the Cars. We have said we do not wish to type these sub-categories/attributes all the time hence we use Page Reference Fields. Which type of Page Reference Field should we use? Remember that our Cars can have only one sub-category/sub-attribute. That’s our cue right there. In order to select one and only one sub-attribute per Car, we need to use the single Page Reference Field. Hence, we categorise our Cars PW site by doing the following (you may follow a different order of tasks if you wish). Create a template to be used by the Car pages. Give it a name such as car-template Create a page for each of your cars and make them use the car-template Create one template to be used by all the main attribute/categories and their children (the sub-categories). We do not need a template for each of the categories/sub-categories. I name my template “car-attributes” Of course you can name yours differently if you wish. Add the fields needed to this template. You don’t need anything other than a title field for each actually. Create top level pages for each main category and assign to them the template car-attributes. As before, give your pages meaningful titles. Do the same respectively for their child pages. E.g., you should have the following child pages under the parent “Year” - 2005, 2006, 2007 and 2008. Create the Page Reference Fields for each of your main categories/parent attributes. Using our example, you should end up with 5 Page Reference Fields (model, year, colour, seats and type). Each of these should be single Page Reference Fields. It’s a good idea, under the BASICS settings while editing the fields, to include some Description text to, include additional info about the field, e.g. instructions. In addition, you don’t want any page that doesn't belong to a particular attribute to be selectable using any of the Page Reference Fields. For instance, when referencing the year a car was manufactured, we want to be able to only select children of the page Year since that is where the year sub-categories are. We do not want to be able to select children of Colour (red, green, etc.) as the year a car was manufactured! How do we go about this? PW makes this very easy. Once you have created your Page Reference Fields, while still in the editing field mode, look under the settings INPUT. The fourth option down that page is “Selectable Pages”. Its first child option is “Parent of selectable page(s)”. Where it says “Select the parent of the pages that are selectable” click on change to change the parent. By now you know where I am going with this. For the Page Reference Field named Year, choose the page “Year” as the parent whose children will be selectable when using that Page Reference Field to select pages. Similarly, do this for the remaining 4 Page Reference Fields. Note that under this field settings INPUT you can change how you want your pages to be selectable. Be careful that you only select the types that match single Page Reference Fields, i.e. the ones WITHOUT *. For single Page Reference Fields, you have the choices:Select - a drop down select Radio buttons PageListSelect Now edit the car-template to add all 5 of your Car Page Reference Fields. We are now ready to roll. Go ahead and edit your Car pages. In each of them you will see your 5 Page Reference Fields. If you followed the instructions correctly, each of them should only have the relevant child pages/sub-attributes as selectable. Do your edits - select year when car was manufactured, its colour, type, number of seats, etc. and hit Save. By the way, note that Page Reference Fields give you access to all the fields and properties of the page being referenced! You have access to the referenced page’s title, name, path, children, template name, page reference fields, etc. This is really useful when creating complex sites. I call it going down the rabbit hole! These properties of the referenced page are available to you on request. It does mean that you will have to specifically echo out the property you want from that page. Page Reference Fields are echoed out like any other field. Example code to access and show content in Simple Multiple Categories model $cars = $pages->find("template=car-template, limit=10, colour=red, year=2006, seats=5"); foreach ($cars as $car) { echo $car->title; echo $car->year; echo $car->colour; } I have made the above verbose so you can easily follow what I'm trying to achieve. The above code will find 10 red 5-seater cars manufactured in 2006. Remember, colour, year and seats are the names of your custom Page Reference Fields that you created earlier. Some sites will have content that belong to multiple categories and multiple sub-categories. We address this below. 3. Complex Multiple Categories Suppose you are developing a site for a school. The school has teachers (duh!) some of whom teach more than one subject. Besides their classroom duties, some teachers are active in various clubs. On the administration side, some teachers are involved in various committees. You know the drill by now. Let’s deal with our basic questions. 1. Q: What items on my site are the main items of interest? A: Teachers. 2. Q: What attributes of our items of interest are we interested in? A: Subjects, Administration, Clubs (Multiple categories) 3. Do these multiple attributes have sub-attributes? A: Yes. e.g., the attribute Subjects has several sub-categories - History, Maths, Chemistry, Physics, Geography, English, etc. (Multiple sub-categories) 4. Can Teachers have multiple sub-attributes? A: Yes. e.g., a Teacher who teaches both maths and chemistry (Multiple sub-categories) Apart from the response to the final question, the other responses are identical to our previous model, i.e. the Simple Multiple Categories. We already know how to deal with multiple categories so we’ll skip some of the steps we followed in the previous example. Since our items of interest (Teachers) can belong to more than one sub-category, we conclude that what we need is a Complex Multiple Category model. In Complex Multiple Categories, items of interest can belong to multiple parent categories and multiple sub-categories both within and without main/parent categories. By now we should know what will be the main criteria for our categorisation. We need to end up with a tree that looks like this: 1. Teachers a. Mr Smith (ex. item of interest) b. Mrs Wesley c. Ms Rodriguez d. Mr Peres e. Mr Jane f. Mrs Potter g. Ms Graham h. Mrs Basket i. Dr Cooper 2. Subjects (ex. main category) a. History (ex. sub-category) b. Maths c. English d. Physics e. Chemistry f. Geography g. Religion h. Biology i. French j. Music 3. Clubs a. Basketball b. Debate c. Football d. Scouts e. Sailing f. Writing 4. Administration a. Discipline b. Counselling c. Exams board d. Public relations e. Education We are ready to build our site. Which type of Page Reference Field should we use? Remember that our Teachers can teach more than one subject and can be involved in various sub-category activities. That’s our cue right there. In order to select multiple attributes/categories, we of course go for the multiple Page Reference Field. Similar to the previous example, create necessary templates and fields for the site. For our multiple Page Reference Fields, remember to select the correct input field types. These should match multiple Page Reference Fields and are marked with *. For multiple Page Reference Fields, the available choices are: Select Multiple* AsmSelect* Checkboxes* PageListSelectMultiple* PageAutoComplete* Remember to add the multiple Page Reference Fields to the Teachers template. Go ahead and test different selectors, e.g. find Teachers that teach Maths and Chemistry and are involved in the Writing club. Whether you get results or not depends on whether there is actually that combination. An important point to remember is that your multiple Page Reference Fields will return an array of pages. You will need to traverse them using foreach (or similar). Example code Complex Multiple Categories model Find the subjects taught by the Teacher whose page we are currently viewing. You can use if statements to only show results if a result is found. In this case, of course we expect a result to be found; if a Teacher doesn't teach any subject, he/she has no business teaching! subjects is the name of one of your custom Multiple Page Reference Fields. echo "<ul>"; foreach ($page->subjects as $x) { echo "<li>{$x->title}</li>"; } echo "</ul>"; There will be situations where you will need to use both Single and Multiple Page Reference Fields (independently, of course). For instance, in our Teachers example, we might be interested in the Gender of the Teacher. That would require a Single Page Reference Field. Summary What we have learnt: Categorising our site content need not be a nightmare if we carefully think it through. Of course not all sites will fit neatly into the 3 models discussed. By providing answers to a few simple key questions, we will be able to quickly arrive at a decision on how to categorise our content. There are at least 3 models we can adopt to categorise our content - single category; simple multiple category; and complex multiple category. In the latter two models, we make full use of PW’s powerful Page Reference Fields to mimic a relational database enabling us to roll out complex sites fast and easy. Useful links: http://processwire.com/talk/topic/3553-handling-categories-on-a-product-catalogue/ http://processwire.com/videos/create-new-page-references/ http://processwire.com/videos/page-fieldtype/ http://processwire.com/talk/topic/1041-raydale-multimedia-a-case-study/ http://processwire.com/talk/topic/683-page-content-within-another-page/ http://processwire.com/talk/topic/2780-displaying-products-category-wise/ http://processwire.com/talk/topic/1916-another-categories-question/ http://processwire.com/talk/topic/2802-how-would-you-build-a-daily-newspaper/ http://processwire.com/talk/topic/2519-nested-categories/ http://processwire.com/talk/topic/71-categorizingtagging-content/ http://processwire.com/talk/topic/2309-best-way-to-organize-categories-in-this-case/ http://processwire.com/talk/topic/2200-related-pages/ http://processwire.com/talk/topic/64-how-do-you-call-data-from-a-page-or-pages-into-another-page/1 point
-
-------------------------------------------------------------------------------------------------------------------------------- for PW 3.0+ please follow this link! -------------------------------------------------------------------------------------------------------------------------------- Croppable Image Module for PW >= 2.5.11 and PW <= 2.7.3 Version 0.8.3 alpha Hey, today I can announce an early (alpha) release of CroppableImage, what was forked from Anttis Thumbnails module. Until now there was a lot of work done by owzim, Martijn Geerts and me. We have solved the issues regarding the list from here: The modules are bundled together so that you only can and have to use FieldtypeCroppableImage for install, uninstall & configure. It uses new naming scheme that was introduced with PW 2.5.0 that supports suffixes. The complete image rendering is delegated to the core ImageSizer, or to any optional hooked in rendering engine. Template-settings are now fully supported, including removing variations when settings have changed. It fully respects settings for upscaling. If upscaling is set to false, you cannot select rectangles smaller than the crop setting. We implemented these enhancements: The GridView now is very nice and compact, and also benefits from the lately introduced setting for $config->adminThumbOptions. Permanent storage of the crop coordinates, quality and sharpening settings are now implemented native. No need to use PiM for this anymore. The usage/display of the Quality and Sharpening DropDown-Selects can be globally disabled/allowed in the modules Configpage. (additionally to that a setting on a 'per field base' is planned.) And the most wanted feature by the community: It gives back a pageimage and not the URL-string. This way you can use it like this: // get the first image instance of crop setting 'portrait' $image = $page->images->first()->getCrop('portrait'); You can further use every pageimage property like 'url', 'description', 'width' & 'height' with it: // get the first image instance of crop setting 'portrait' $image = $page->images->first()->getCrop('portrait'); echo "<img src='{$image->url}' alt='{$image->description}' />"; And you can proceed further image rendering with it: // get the first image instance of crop setting 'portrait' and proceed a resize with imagesizer $image = $page->images->first()->getCrop('portrait'); $thumb = $image->width(200); // or like this: $thumb = $page->images->first()->getCrop('portrait')->width(200); // and if you have installed Pia, you can use it here too: $thumb = $page->images->first()->getCrop('portrait')->crop("square=120"); The only downside with this is that when you (as the site developer) have enabled the usage of DropDown-Selects in the images editor, you do not know the values the editors have chosen for the images. As a workaround for this you can use the getCrop() method with a second param. This is a PW selector string. It can contain as many of the known pageimage options like 'quality', 'sharpening', 'cropping', etc, as you need, but none of them is required. But required is at least one setting for 'width' or 'height': $image = $page->images->first()->getCrop('portrait', "width=200"); $image = $page->images->first()->getCrop('portrait', "width=200, height=200, quality=80"); $image = $page->images->first()->getCrop('portrait', "height=400, sharpening=medium, quality=75"); . . You can get the module from GitHub: https://github.com/horst-n/CroppableImage (Better Docs are coming soon) Screenshots Related Infos A good setting in site/config.php for the AdminThumbs are: (height=>200 and scale=>0.5 !) $config->adminThumbOptions = array( 'width' => 0, 'height' => 200, 'scale' => 0.5, 'imageSizer' => array( 'upscaling' => false, 'cropping' => true, 'autoRotation' => true, 'sharpening' => 'soft', 'quality' => 90, 'suffix' => array(), ) );1 point
-
Then your path must be wrong. I tested and it works fine. Normally, $this->config->paths->ModuleName should give you the path on disk to a module's folder but I've found out that for Fieldtypes that live inside their own folders (such as FieldtypeComments), it doesn't work. For those 'outside' such as FieldtypeDatetime, you will get the path on disk, e.g. F:/vhosts/k.dev/wire/modules/Fieldtype/ So, you need to try something like this (hard-coded, I know ): public function init() { $path = $this->config->paths->modules . 'Fieldtype/FieldtypeComments'; require_once($path . '/Comment.php'); }1 point
-
Hey Daniel, The themes are set on a per-user basis as part of your profile, or you can set Reno to be the default for all users by editing your /site/config.php There is also a module that let's you edit config.php from the admin. https://github.com/ryancramerdesign/ProcessWireConfig1 point
-
I think $comments = wire(modules)->get("Comments"); should work. Probably.1 point
-
Thanks @horst, if you see my mistakes and no need things or any useful things let me know please1 point
-
@Mats thank you, but that does not quite apply to my situation. But I just found the solution: In the single image field settings in Details tab, I needed to switch from "Single item (null if empty)" to "Array of items" Now I can use the single image min my frontend form Somehow the processInput method can only handle arrays for file fields1 point
-
Hi! Here's the solution: https://processwire.com/talk/topic/9827-single-image-upload-on-frontend-doesnt-work-correctly/1 point
-
Just off the top, I don't believe the comment module is autoloaded, so you'd have to reference it prior to instantiation.1 point
-
I think the problem is mostly a wrong mental mapping from the term "page". Most people will at first think about pages as "pages to be seen on the frontend", whereas a page is ultimately just a flexible container holding information, while adhering to a contract called template. It's nothing special about it, but just as one does need to learn how models work in MVC frameworks it's a likewise process to see what's possible with pages.1 point
-
Update: Version 0.1.3. Fixed bug where on uninstalling the module, menu pages in the trash would not get deleted, hence throwing an error when the uninstall routine tried to delete their template1 point
-
This improvement could come handy, for me it comes up regularly. API method to check if image is a default image: would return true if selecting a page instead uploading an image, using the admin "Default value (when empty)" field (eg. "isDefaultValue" or "isPlaceholder"). Currently I have to check for a file name ("no-image.png"), obviously not the best way.1 point
-
Hi, and welcome to Processwire. Using your cpanel filemanager or do it your self with zip over ftp goes many times faster when working online on a host. The intermediate profile with delayed output is the most interesting one to work with. It let's you setup any website with the most efficient structure Starting to learn processwire is best done locally with an apache/mysql stack (lamp,wamp,mamp,etc.) You can use the Site Profile Exporter module for easy switching between your own websites as a profie http://modules.processwire.com/modules/process-export-profile/1 point
-
I'm really not sure if this works every time. Lately I have tricked my self with using dashes - - - in fieldnames and not underscores _ _ _ . Fieldcreation was via API, where the fieldname was stored in a class constant: const MYFIELDNAME = 'my-new-fieldname'. The new fieldname of the created field worked out as: 'my_new_fieldname'. Later in the code, where I want access one field with a selector like $page->get("name=" . CLASS::MYFIELDNAME), it doesn't work. I'm not sure if this was with fields of type text / integer or only Page, but I perfectly remember that it hasn't worked. ---- There was also this: https://processwire.com/talk/topic/8709-croppableimage/page-2#entry86866 (read this and the two following posts)1 point
-
I replaced $timeFormatJS = str_replace('h24', 'h', $timeFormatJS); with $timeFormatJS = str_replace('hh24', 'HH', $timeFormatJS); in InputfieldDateTime.module (line 160).1 point
-
Just an update for anyone who may hit this issue in future. Wrapping your $session in an the following if statement works. $(!$config->ajax) { } It's because the front-end editing when activated reloads the page using ajax. More on it here: https://github.com/ryancramerdesign/ProcessWire/issues/1602#issuecomment-172309783 - Thanks Ryan for clearing it up.1 point
-
Update: Version 0.1.1 And, we are back! Thanks for waiting! Fixed bug relating to getLanguageValue() (issues #22 and #25). Thanks @all who reported, tested,and fixed the issue. Fixed bug where 'has_children' would not be applied to a menu item whose children were included 'natively'. Switched to $this->wire('pages') from wire('pages') (and similar). As per request at issue #18, added option 'default_class' to enable application of a default CSS class to every menu item at API level. Thanks @jlahijani. You can use this API-level option to add custom CSS class(es), e.g. Bootstrap or Foundation ones.1 point
-
1 point
-
Yay! This update has me rather excited, and I can already see an overhaul of our course booking system coming up in the near future. Nested repeaters and field templating are just the things to streamline this quite spectacularly. Dynamic Ajax loading is going to be such a treat too! Ryan, if you keep up PW's innovation speed like this, I'm sooner or later going step on my tongue while I race to make us of all these new possibilities!1 point
-
Just when you think it wasn't possible to like ProcessWire any further. This is amazing news and will open up so many opportunities for complex data, very much appreciated!1 point
-
There's no "creation of a new page array", because $kunden->unternehmen is already the pagearray. It's just converted in a list of id's for stringified output. You can directly loop over the list like so: foreach ($kundenliste as $kunden) { foreach($kunden->unternehmen as $unternehmen){ echo $unternehmen->title; } }1 point
-
My menus work like this First create a "menu" template, a simple empty template that will hold "menu-item" pages as children. Then create the "menu-item" template that can hold 'menu-item' pages as children, fill it with these fields : - (title field) The title for the menu - (item field) A page reference (Single Page or NullPage) field that will link any page in the site except pages with menu or menu-item template. - (isExternalLink field) A checkbox that tells if the link is outside the site. - (externalLink field) a Textbox that holds the external url if the checkbox isExternalLink is active. You can add many additional fields depending on your needs, like css, js, or other information. When that is done just create a page named "Menu" with the "menu" template, later add children pages with the "menu-item" template. Now you have a menu that can be rendered like any other page in processwire. $menu = $pages->get('/menu'); foreach($menu->children as $menu_item) { if($menu_item->isExternalLink){ echo "{$menu_item->externalLink}"; } else { echo "{$menu_item->item->url}"; } } With this approach you can rely on the Processwire backend to give order to the items and create as many children and deep levels as you like1 point
-
I found the solution: you have to include $user->userimage->removeAll(); // wirearray before this line of code $user->userimage = $upload_path . $files[0]; This removes the image array in a first step and then loads the new image in the database.1 point
-
From the api side image fields are always multi-value. Only the "output-formatting" state does allow you to call the first image automatically. Therefore you need to clear the image field manually before adding the new image.1 point
-
Hello all, I was wondering what the most elegant solution would be to find out when the last time a change was made to any regular pages (not admin pages)? Cheers. Update: Sigh was trying to overcomplicate things again. The easiest solution is: $page = wire("pages")->find("sort=-modified")->first()->modified;1 point