Leaderboard
Popular Content
Showing content with the highest reputation on 09/24/2014 in all areas
-
Well, soma alone is a "feature" that most software projects can only dream of.8 points
-
Stroke upon stroke... Another one online: http://aureliusinvest.com/en/ (english) and http://aureliusinvest.de (german) German Investment Company. Porting old website from MODX to PW (by hand mostly), added some more emotional imagery and a bit more what they actually do and how they work. Nothing special to say about the used modules, it is mainly content and images which has to be managed by PW.5 points
-
@adrian: both of your ideas are included now: https://github.com/netcarver/PW-ProcessDiagnostics/blob/master/DiagnoseModules.module3 points
-
Please think for 5 seconds before posting! You are opening a php tag inside a php tag. Joss suggested you do that because you weren't clear if you were doing this inside or outside a php tag. You have two choices: <!-- Outside the PHP tags--> <div id="button3" class="button_style"><a href="<?=$pages->get("/kontakt/")->url ?>">kontakt</a></div> or <?php // inside the PHP tags. You are using single quotes, so you can't echo variables without closing them echo '<div id="button3" class="button_style"><a href="' . $pages->get("/kontakt/")->url . '">kontakt</a></div>'; ?>3 points
-
Glad you figured it out. Unfortunately $_SERVER['SERVER_NAME'] can't always be relied upon because some cases have it populated with something other than the hostname of the current site (like the hostname of the server itself rather than the site). Though you also can't rely on $_SERVER['HTTP_HOST'] either, as that can be manipulated by the request. If you need the capability to automatically switching DB configs depending on dev or live, your best bet is probably to copy your /site/config.php to /site/config-dev.php and only keep that file in your dev environment. Your /site/config.php will be ignored when /site/config-dev.php is present, enabling you to accomplish the same thing you are now, so long as you don't upload config-dev.php to your live site.3 points
-
Simple ProcessForgotPassword (core module) integration done. "Forgot password?" link added as form field after login form password field if ForgotPassword module is installed.3 points
-
Ryan, next time you're are messing with the module, fancy putting in a drop down for font size on Ace? For us old blokes, you know......2 points
-
This is the second site for my music production company using ProcessWire - the first was over a year and a half ago. http://dancingbear.co.uk Very simple site incorporating a version of jplayer - the player is loaded via ajax and is actually incorporated into the page using Hanna Code. Site runs with ProCache and cloudflare. It is not the most awe inspiring site out, but then, audio is not known for having a lot of pictures associated with it! The logo is based on one that a friend drew for me 20 years ago. I have decided to reuse it and redraw it. Slight issue in that the contact form that worked fine on my development server but I am not getting any mails from the production server. I have opened that up as an issue at: https://processwire.com/talk/topic/7685-not-receiving-mail-from-form/ NOTE: I have turned off procache for the moment while I check on a couple of issues. Back on now, as is cloudflare ... is that overkill? Edit - note for anyone using cloudflare (who are very good, mostly). They are not appropriate for streaming audio or video sites. Their advice is to create a subdomain and to put audio files in there, then make sure that subdomain is NOT being cached by cloudflare. Or you can put it on a CDN somewhere. That way the main domain is properly served by cloudflare while the media is brought in from elsewhere.2 points
-
Hi Mike Anthony Yes, I read about heredocs, actually that looks nice as you don't need to use escape \ and can write the html line as it is. Somehow we are hooked on echo with escapes. Thanks for the link you included. Now this part of the read in the text of that link is interesting: Quote: Heredoc's are a great alternative to quoted strings because of increased readability and maintainability. You don't have to escape quotes and (good) IDE's or text editors will use the proper syntax highlighting. A VERY common example: echoing out HTML from within PHP: $html = <<<HTML <div class='something'> <ul class='mylist'> <li>$something</li> <li>$whatever</li> <li>$testing123</li> </ul> </div> HTML; // sometime later echo $html; Easy to read. Easy to maintain. The alternative is echoing quoted strings, which end up containing escaped quotes and IDEs aren't going to highlight the syntax for that language, which leads to poor readability and more difficulty in maintenance. end quote. Seems you can also use it in other ways like in sql: $sql = <<<SQL SELECT * FROM table SQL;2 points
-
Just my two cents: When using HTML in (that is, within a function), I tend to use heredocs, which makes code visualisation easier - especially when you're using an editor like Sublime Text, or something along those lines. In your case, you could do the following: print <<<HTML <div id="button2" class="button_style" onclick="location.href='page2.html';" style="cursor: pointer;">product</div> HTML; You'll noticed I used print instead of echo, as print is a better option, in my opinion, for heredocs and nowdocs, as you only ever need to print one at a time.2 points
-
Wow! You guys are amazing! PW is awesome, but the community really is the killer "feature". Thanks guys2 points
-
I was trying with my 160k testinstall Diogo's code doesn't work really as it has no correct start value and that would be something like the page's position in the result - 2 or something. So I tried with diogos approach and came up with adding a url segment to each article link in the list like /articleurl/1 to be able to get the position on the article page. //That would generate the list $session->list_selector = "template=news-entry, summary*=europa, sort=-date"; $limit = 10; $list = $pages->find( $session->list_selector . ", limit=$limit"); $start = $input->pageNum ? $limit * ($input->pageNum - 1) : 1; // $input->pageNum is the page from pagination foreach ($list as $key => $p) { $pos = $start + $key + 1; echo "<li><a href='$p->url{$pos}'>$p->title</a></li>"; // add position to the url } echo $list->renderPager(); And on the article page if($session->list_selector && $input->urlSegment1) { $pos = (int) $input->urlSegment1; if(!$pos) return; $limit = 3; $start = $pos == 1 ? 0 : $pos - 2; $selector = "{$session->list_selector}, start={$start}, limit={$limit}"; $array = $pages->find( $selector ); $prev = $page->prev($array); $next = $page->next($array); if($prev->id) echo "<a href='" . $prev->url . ($pos-1) . "'>Prev</a> "; if($next->id) echo "<a href='" . $next->url . ($pos+1) . "'>Next</a> "; } Works fine with a search with about (7) thousands of results in about 0.1 - 0.2 sec. This would be cacheable if you even construct the url using the category (if that's what you filter for only) and have those even cached results (hence own url). Another approach would be to cache a text file with the result (to not store big amount of data in session) and save and load that depending on the filter. A delimited list of ID's and use it to search to get the prev and next item in the list. Not sure this would complicate things but then the DB don't need to query each time (if that's at all a problem.)2 points
-
Just to correct the quote above, delayed output is more scalable, not less scalable. Direct output is what doesn't scale, but it doesn't really matter when it comes to the default profile. I have worried about this aspect a little bit: making something as easy-to-understand as possible, versus showing what is a best practice. Delayed output is just as simple as direct output (not to mention it uses a lot less code), but it's not as easy to understand at the very beginning. On one hand the PHP developers evaluating ProcessWire cringe when they see the direct output method used in the old default (now classic) profile. On the other hand, beginners find it easier to relate to since it's common in other platforms. Both are our audience. If people think delayed output isn't beginner friendly enough, perhaps we need to have two versions of the default site profile. A beginner edition and an intermediate edition. Attached is a beginner edition of the default site profile. @Woop if you or anyone else gets a chance to take a look, please do and let me know if you think this is a more beginner friendly approach. I think it probably is, even if it isn't an approach I'd suggest someone use for anything but smaller sites. site-beginner.zip To install, just grab a fresh copy of ProcessWire 2.5.0+. Place the contents of the zip in a /site-beginner/ directory and then load the installer from your browser. For site profile, select "Default (Beginner Edition)". The readme file in /site/templates/ has also been updated in this profile to reflect the structure of the template files. As for re-writing the text in the default profile (something mentioned way earlier) I agree on this and I need to talk to Joss. But I think getting the template files as simple as possible is a bigger priority at the moment. I think a lot of people installing CMSs for evaluation are more interested in the system and templates than in what demo content is in the fields. But for those that do read it, we can do better.2 points
-
Just wanted to throw in my two cents. If you come at it as a front-end developer that's a complete beginner to CMSs, then PW should be very easy to get going. It's built around working the same way that existing web technologies work… Pages map in the same way that URLs do… Template files are just plain HTML/PHP files… the API is largely the same as a front-end API (jQuery)… and so on. So if you know your basic web technologies outside of CMSs, then you won't find a simpler system than ProcessWire. The problem is most other CMSs don't work that way. So the line gets more blurry when you've become used to the terminology and approach of another CMS, because PW can be quite different. Sometimes you have to unlearn what you know from elsewhere in order to appreciate the simplicity of PW. People are always trying to find complexity that isn't there, especially those that grew up on other platforms. PW is a system that rewards you by being curious. We aim to show you how to fish so that you can catch the big fish. We're not here to catch the fish for you. You don't have to know anything about fishing, but you should know how to yell for help if you fall in the water. And you should be willing to learn by example. I learn best by example, so this is the way I tend to teach too (and I recognize not everyone learns the same way). PW is a CMS and CMF, not a website builder. If you are curious and willing to explore, you'll find it is very simple indeed. Certainly far simpler than even WordPress in creating a custom website. You do have to come from the point of view of "I want to create and have the system adapt to me" rather than "I will create something based on what the system provides." If you already know what you want to create and it's something unique, you won't find a simpler path to get there than PW. WordPress is a different beast, in that it's basically saying "YOU WILL CREATE A BLOG or modify this blog and call it something else." Some people like that underlying structure… "okay, we're starting with a blog, what can we do with it?" Others do not like that underlying structure. Our audience consists of those that want to have a system support their original creation rather than mash up an existing creation. There was a PDF posted earlier that I think hit upon some good points, and I appreciate the effort that went into putting it together. The fictional character being scripted in the dialog is not our target. I can go into specifics if anyone wants me to, but I was definitely left feeling at the end of it that we have to be careful about hand-feeding too much or else we'll start attracting people beyond our support resources. Folks that want the fish cooked and filleted rather than folks learning to fish. Perhaps in time we will want to attract more of the consumer-type audience, but currently I don't know how to support users looking to find all the answers in a sitemap file. Keep in mind that unbridled growth is not necessarily desirable. Most of us don't get paid for most of the work we do here and we do best if we grow in a more healthy manner, attracting more thoughtful designer/developers that are here to learn and also contribute. Obviously the author of the PDF is one of the thoughtful ones (and the PDF is a great contribution), even if his fictional character isn't necessarily, but we'll welcome him anyway. But we will definitely be going through the PDF in more detail to learn and improve from it where appropriate, while keeping our audience in mind. I think we're doing something right, because our audience is growing rapidly. I'm nearly full time on ProcessWire now, and it's still difficult to keep up with everyone. At present, I like that our audience is largely open-minded, curious and thoughtful designers and developers. Somehow we've attracted an incredible quality of people and that's what makes this place great. We could not ask for a better group of people here. I'm reluctant to lead PW towards a website builder direction because I think that's when the quality of the community could go down, as people come looking to eat fish rather than learn, catch some fish, and throw some back. The reality is that part of our long term goals include converting the rather large audience that has outgrown WordPress into ProcessWire users. I'm convinced that we do that by giving them more ProcessWire, and not more WordPress. But at the same time, we always have to keep an eye on WordPress and learn. They've been lucky no doubt, but they are also doing many things right. So we have been and always will be working to make the WP-side of users more comfortable in ProcessWire, while also trying to help them grow by distancing them from the limited WP mindset.2 points
-
1 point
-
Dynamic Roles are a powerful access control tool for ProcessWire. They pick up where traditional roles leave off, and allow you to assign permissions at runtime based on any factor present with the user. Once a user receives one or more dynamic roles (at runtime), those dynamic roles then specify what pages the user can view, edit, or add children to. If traditional roles are a sledgehammer, Dynamic Roles are a scalpel, allowing nearly any finely tuned access control scenario. Traditional ProcessWire roles are limited to assignment of view/edit/add access on a per-template basis. Dynamic roles go outside those limitations and enable you to assign that access based on any factors present with a page (i.e. match any field values). Dynamic Roles assign new access, but do not revoke existing access provided by traditional roles. As a result, Dynamic Roles can be used together with traditional roles, and the two work beautifully well together. Though Dynamic Roles can also replace all situations where you would use traditional roles for access control assignments. If using Dynamic Roles to assign page-view access, you would typically want to use traditional roles to revoke view access from at least the "guest" role at the template level. Then use Dynamic Roles to assign view access to those pages in a more granular manner. This module directly affects the results of all page getting/finding operations by applying the access control directly to the database queries before pages are loaded. As a result, it is fast (regardless of scale), pagination friendly, and requires no further intervention by the developer other than configuring the dynamic roles as they see fit. Because it relies upon new features present only in ProcessWire 2.4.6+, it requires the current dev branch. Sponsored by Avoine Concept by Antti Peisa Code by Ryan Cramer PLEASE NOTE: This module is in pre-release state (like the PW dev branch it requires) and is not recommended for production use just yet. Though we do appreciate any testing and/or feedback that you are able to provide. While not required, this module benefits from ProFields Multiplier. If you have ProFields Multiplier installed before installing this module, it will make this module more powerful by making all of your access control selectors have the ability to use OR-group conditions. Depending on your access control needs, this enables you to accomplish more with fewer Dynamic Roles. How to install Make sure you are running ProcessWire 2.4.6 (dev branch) or newer. Download from GitHub (we will add this module to the Modules directory later). Place all files from this module in /site/modules/DynamicRoles/. In your admin, go to Modules > Check for new modules. Click "install" for the Dynamic Roles module (ProcessDynamicRoles). Click to Access > Dynamic Roles for the rest (see example and instructions below). Example and instructions Lets say you ran a Skyscrapers site and wanted a role enabling users with "portmanusa.com" in their email address to have edit access to skyscrapers designed by architect John Portman, with at least 40 floors, and built on-or-after 1970. Yes, this is an incredibly contrived example, but it is an example that also demonstrates the access control potential of this module. 1. In your admin, you would click to Access > Dynamic Roles. 2. Click "Add Dynamic Role". Enter a name for the dynamic role, like: "skyscraper-test-editor" and save. 3. Under "Who is in this dynamic role?" section, click "Add Field" and choose: Email => Contains Text => "portmanusa.com". This will match all users having "portmanusa.com" in their email address. 4. Under "permissions" check the boxes for: page-view and page-edit. 5. For this contrived example, we will assume the user already has view access to all skyscrapers, so we will leave the "What can they view?" section alone. 6. For the "What can they edit?" section: Click "Add Field" and choose: template => Equals => Skyscraper. Click "Add Field" and choose: architect => Equals => John Portman. Click "Add Field" and choose: floors => Greater Than Or Equal => 40. Click "Add Field" and choose: year => Greater Than Or Equal => 1970. 7. Click Save. Now users matching the conditions of your dynamic role will be able to edit the matching pages, but not any others (unless assigned by traditional roles).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
-
You've been using MODX but now you've found ProcessWire. It’s totally amazed you and you can’t wait to get started. But…you are wondering where everything is. If this is you, read on… This guide is primarily aimed at those who are coming in from MODX and wish to know how to accomplish “MODX things” the “ProcessWire (PW) way”. This is not meant to be a full blown PW tutorial. It will focus on some key MODX concepts/tasks and how to accomplish those in PW. It will cover, whenever possible, both versions of MODX - Evolution and Revolution. The guide assumes that you’ve at least logged into a PW site and/or viewed a demo. The Table of Contents mostly reflects MODX terminology. Table of Contents 1. Manager 2. File System 3. Resources 4. Templates 5. Template Variables (TVs) 6. Template Files 7. Snippets 8. Modules 9. Plugins 10. Chunks 11. Miscellaneous 12. Examples - the PW way… a. Template Variables b. Snippets c. Modules d. Plugins e. Chunks 1. Manager In PW, the “manager” is referred to as the “Admin”. The default location of the Admin is www.yoursite.com/processwire. As of PW 2.3, you can rename the Admin to anything you wish during install. Just be careful to remember the name you use or you will be locked out! (If that happens, there are ways to get around it though). Logging into Admin, you will notice a tree just like in MODX. The Admin runs on jQuery UI and as you’ve seen, it is insanely fast! Don’t be fooled by its simple facade. PW is a really powerful CMS, highly extensible and very easy to use. Customising the PW admin is very easy. There are a number of custom themes available. It is also trivial to make yours. Custom Admin themes go into the folder site/templates-admin/. You can have only one theme at a time. On a related matter, if you wish to create a custom Admin page, it is easy to do so. See this thread for more info. 2. File System After installing PW, you will see two main folders; “site” and “wire” in your file system. Site is where all things related to your site reside. This is your playground and will survive an upgrade. Wire houses the Core. You will never have to go into that folder. 3. Resources In MODX, Resources can be many things (documents, etc.). There is no such term in PW. However, the most important “resources” you need to know about in PW are page and pages. Pages are a very powerful concept in PW. Page can refer to your website’s frontend pages, i.e. what can be viewable by your website users. I say can be for a reason. There are many uses for Pages in PW. This can be confusing to newbies but once you get the concept, you will appreciate the power of the system. Just because something is a Page does not mean it has to be viewable. It can have other uses such as a container that holds data for use by other Pages - in this case the Pages do not have to be displayed on the frontend. In fact, everything you see on the PW tree is a Page. That’s right; even the Admin and its components (Users, Roles, etc.) are all Pages! Still confused by Pages? Have a read here. Pages reside in the PW tree - you may have noticed . You can drag and drop pages to move them around. If drag and drop doesn’t work you probably have MySQL 5.0.5.1 installed. Upgrade your MySQL and you are sorted. The root of your site is the uppermost Page in the tree. In the default PW install this is called Home. You can change the name to something else. The default PW install comes with a number of Pages pre-installed. Try editing a Page. All those Fields you see on that Page when under the “CONTENT” tab? They are not default Fields. They are all Custom Fields! Yes, not even the Title! The only required Field for a Page is “name”. You find this under the “SETTINGS” tab on the page edit screen. More about Fields below… Other related stuff: Menuindex: As an aside, if outputting something like a menu, unless you state otherwise, it will reflect the tree hierarchy. Show in Menu: This functionality is covered by the Page status, whether hidden or not. Hidden pages do not get output on menus (more about menus later) unless explicitly stated so using PW API selectors (see below). Menu Title: No such term in PW. You can name your menu items what you wish to name them. Very important: All Pages must be assigned a Template. 4. Templates In PW, Templates mean something slightly different compared to MODX and many other CMS. MODX describes templates as: That is not entirely true of PW Templates. In PW, the term Template is used in the sense of the English definition of the term: PW Templates serve as a pattern for the foundation of your Pages. By foundation, I do not mean the HTML or CSS. Rather, the Template servers as blueprint for your Pages. What is available to the Template is available to the Page that uses it. Templates establish a pattern for the Pages by the inclusion of Fields to the Template. A Template can have as many or as few Fields as you wish. You can create as many or as few Templates as you wish. You can easily change the Template a Page uses when editing the Page. See under SETTINGS. Note that if you have Fields on that Page that are not in the Template you are switching to, those Page Fields will be lost! PW will warn you about this when switching Templates though. OK, so how do you show “Resources to the world”? That will be the work of Template Files which we’ll look at in section 6. 5. Template Variables A powerful feature of MODX is Template Variables (TVs). If you loved MODX TVs you will absolutely adore the PW equivalent. In PW, TVs are known as Fields. You can define your own Custom Fields. In fact, you will need to create your own in most cases. This is because PW does not have any required Field except for “name”. It is perfectly reasonable to have a Page with only the name Field! Many people do add at least a Title Field for such Pages. In the default PW install, the reason you see the Title Field in all Templates is because it has been set as a “Global” Field under the ADVANCED settings of the Field (edit the Field to see this setting). There are many types of Fields to hold all sorts of data - images, texts, urls, passwords, reference to Pages, etc. You can call your Fields anything you wish. You can call the Field for your main content “body”, or “stuff”, or “content” or whatever you wish as long as you follow the naming convention, i.e. “[a-z], numbers [0-9], or underscores (no dashes or spaces)”. Fields are reusable across different Templates. The order in which they appear on your Page follows the order in which they are arranged on your Template. However, it is important to note that: The order in which Fields appear on your page and/or the inclusion of a Field on your Page does not mean that: The Field will be output on the Frontend. The inclusion of a Field on a Page does not automatically mean it will be output; PW does not make that decision for you. It only makes the Field available to you to use as you require. You can output all or none or few of the Fields on your Page. The order in which Fields appear on a Page does not mean the same order will be reflected when you output the Page. You make that decision. Also note that you are able to arrange Fields side-by-side on your Page (via settings on the Page’s Template) to mimic your site’s layout or for other visual/ease-of-use purposes as you edit the Page in the Admin. You can also give each Field a label and a description. These will appear above each Field when editing a Page. In most cases, the content of Fields will be saved directly to the database. In the case of file related Fields, the path to the file will be stored in the database. There are no direct equivalents of MODX TVs “@Bindings” (data sources). These are inherently built into the different types of Fields. Note that you cannot run PHP code within Fields (so no @Eval). This is by design. Fields are a very powerful and much loved concept in PW. Just Google "custom fields cms" and you’ll see what comes up tops. 6. Template Files So far, we've seen that you create Fields, add them to a Template you've created and edit a Page using that Template to input your content into that Page’s Fields. So far so good but how do you output the content to the world? You do this via Template Files. Template Files live in /site/templates/. You have to create your own Template Files. In MODX, a Template will have both system fields, e.g. body, title, etc. and custom fields (TVs). Rendering a Template is achieved by adding MODX tags to your Template. In PW, in order for the content of your Page to be seen by the world, its Template must have a Template File (or there must be some other Template File associated with a different Template that is dynamically pulling and outputting elsewhere the content of a Page whose Template does not have a Template File). This does not mean that all content within a Page will be automatically output by the Template File. No; in the Template File you can choose to render all or some Fields present in the Pages using that Template or none at all! You tell the Template about the associated Template File when you create/edit the Template. PW assumes that there is a Template File with the same name as the Template in /site/templates/ and will tell you if it does not find one. However, you have two other choices. You can either enter an alternative name for your Template File or tell PW you do not wish to have a Template File for that Template. This means that a Template does not require a Template File. Obviously, in such a case, you will not be able to directly output the content of the Pages using that Template. In some cases, that is exactly what you want . As you get to know more about the system, you will find out how powerful and flexible the PW Template system can be. For instance, you can use your Template as a controller. That’s beyond this guide but feel free to search the forums for more info. Template Files are typically PHP files with logic to dynamically output your content. In most cases, Template Files are HTML with PHP tags inserted to output your content. The PHP in the Template File will in most cases be PW API. Hence, you will see things like $page and $pages in Template Files. The former always refers to the current Page and the latter to any other Pages in the system. These are very powerful variables in PW and give you access to ALL information about ALL pages including their Fields and whether those are empty or not, etc. See below for more info about these variables and have a look the docs too. Note that Templates do not care about what’s in your Template Files. In fact, they won’t even check. All they want is for you to tell them if and how you wish your Pages' contents to be rendered. Your Template Files can even contain pure HTML (although that won’t be dynamic!)! Your Template Files can have references to other things related (or not related!) to the Page using that Template File. For instance, within your Template File, you can pull in the 10 latest “posts” from your Blog or the Children Pages of that Page. There are just too many possibilities to list them all here. Don’t let the PHP in Template Files scare you if you are no coder. I am no coder but I am able to use PW. You will only need to know at least some very basic PHP to use PW. The most important are: echo; foreach; and if… Anything else is a bonus in most cases. In addition, you will need to know how to use the two most important PW variables - $page and $pages. With these two, most of what you would have done in vanilla PHP is covered. They are easy to use and to understand and very much follow the jQuery concept. Check out the docs to learn more. 7. Snippets In MODX, Snippets are the method by which MODX allows you to run dynamic PHP code in any of your pages. In PW, the term Snippets does not exist. What!?! Not to worry; in PW MODX-like Snippet functionality can be achieved in two ways: Template Files: Most PW Template Files are essentially dynamic PHP code. That’s Snippets for you right there. PW Modules: PW Modules do what MODX Snippets do and more (see below). It’s just an issue of terminology. For instance, the popular MODX Snippet WayFinder has a Module counterpart in PW. This is the Module Markup Simple Navigation. However, you do not need to use the Module to create a menu in PW. You can do the same thing using PHP in your Template File. See the default PW install for a simple example. Check out section 12 of this guide for example “popular-MODX-Snippets-to-PW-how-tos”. 8. Modules MODX Evolution defines Modules as “a program that can only be executed from within the manager.” There are PW Modules that fit this definition, for instance, the Module Batcher which is equivalent to the MODX Revolution add-on Batcher. However, there are other PW Modules that are executed in the frontend, e.g. Markup Simple Navigation previously mentioned. In fact, in PW, a Module is PHP that extends the functionality of PW. Modules contain PHP classes that adhere to PW’s Module interface. 9. Plugins In MODX Plugins are PHP code that are set to execute during certain system events. In PW, although the term Plugin does not exist (except maybe in reference to Modules), MODX Plugin functionality is easily doable in PW. This is achieved via Hooks. There is one difference though. In MODX, Plugins are standalone code you can download and install. You cannot download and install PW Hooks. Instead, PW contains many methods that you may hook into in order to modify the behaviour of the method. In other words, PW offers the ability to hook into its processes/events and manipulate them before or after the event or even replace them, etc. Hooks are usually invoked inside Modules. However, Hooks may be attached from anywhere that you use PW's API, for instance in Template Files. The average PW user will not need to use Hooks. For more info about Hooks check the documentation. 10. Chunks MODX defines Chunks as “bits of static text which you can reuse across your site”. There is no equivalent term in PW. You can, however, easily create Chunks in PW. You can create Chunks as a Page that contains various Fields each of which can act as a Chunk. This means you can have Chunks of all sorts of data. You can then set the Page you create to hold your Chunks as hidden (not available to searches). The Page can also be assigned a Template without a Template File to further limit frontend access. It can also be created as a child/grandchild of the page Admin. That will limit access by User (e.g. login required to view it in Admin). Accessing the Fields of that Page as your Chunks using PW API is quite trivial really. Since you can use labels and descriptions to further define each of your Pages’ Fields, this makes it quite easy to describe what each Chunk is for and/or give instructions on how to use the Chunks. See this example for more info. You can also simply use text files to pull into your content as Chunks. Personally I prefer using Pages as Chunks when I need to. In MODX, it is usual for many Snippets to use Chunks (HTML + placeholders) to structure their output (i.e. tpl Chunks). You do not need to do this in PW. Code output can be wrapped in HTML right within the Template File. The important thing to remember is that any Field in any PW Page is available to any other Page and any Template File. Cross-referencing Fields and Pages is child’s play. Seriously; it is that easy. 11. Miscellaneous Tag Syntax: PW does not use a templating language (tagging syntax) like MODX does. See this article why this decision was taken. I agree 100% with the approach and have come to realise its many benefits over using a templating language. However, there are two Modules that allow you to use template language tags in PW. I have never used them so cannot comment further. They are here and here. Settings Page: PW has no settings page like MODX. Many settings are set in the /site/config.php. Other MODX settings equivalents are interspersed in various places including caching content on a Template by Template basis and in Modules. You can also store custom settings needed for your site in the /site/config.php. You can even use Pages to store your settings as mentioned in section 10 (Chunks). Modularity: PW is a very modular system. The whole of PW is made up of Modules (Core Modules) that accomplish different tasks. 12. Examples - the PW way… In this section I will show you equivalent MODX versus PW add-ons as well as how to accomplish various task using PW “Snippets” equivalent. a. Template Variables As previously mentioned, MODX TVs are PW Fields (although PW Fields are more versatile). Outputting the contents of your Fields is very simple. echo $page->name_of_your_field; This gives you the contents of the Field in the current page. Works slightly different for image fields though. For other pages echo: One page $pages->get(ID or PATH or NAME, etc.)->name_of_your_field; //note replace ID with ID of the Page you want, etc. Many pages $pages->find("selectors"); //this will return an array. You can then go through the array using foreach as shown in the examples below to output the field(s) contents MODX - output main content of Page //MODX Evolution[*content*] //MODX Revolution[[*content]] ProcessWire - output main content of Page //ProcessWire echo $page->content;//note; this assumes you have a Field called content in the Template of the current page. In ProcessWire you can find Fields of other pages like so $fruits = $pages->find("template=yumyum, limit=10"); foreach($fruits as $fruit) { echo "<li><a href='{$fruit->url}'>{$fruit->title}</a></li>"; } //find 10 Pages that use the Template yumyum and echo their url and titles in a list. From these examples, you can see the elegance and flexibility of TVs done the PW way. Since there is separation between a Template and a Template File, you can conditionally echo out the contents of Fields found in Pages. b. Snippets Common MODX Snippets and PW equivalent Modules 1. WayFinder: Markup Simple Navigation or code in Template File (see head.inc in default PW installation for a simple menu). 2. Ditto (Evolution) and getResources (Revolution): Functionality inbuilt in PW. Use $page and $pages variables + selectors to find anything, anywhere. 3. Jot (Evolution) and Quip (Revolution): Comments Module is part of the PW Core. It is not enabled by default. You will have to enable it in the Admin. See also the related Comments Manager Module. 4. eForm (Evolution) and FormIt and FormItBuilder (Revolution): There are various Form parser codes in the Forums. There is also a commercial Form Builder Module. It’s not expensive, is developed by PW’s lead developer and proceeds support the PW project. 5. MaxiGallery (Evolution) and Gallery (Revolution): Presently, there is no equivalent. However, it is quite easy to build a photo album. See this tutorial in the wiki. There is also an Images Manager Module (still in alpha though). 6. AjaxSearch: Ajax Page Search Module. 7. Breadcrumbs: Quite easy to accomplish using PW API. See default PW install for an example. 8. FirstChildRedirect: Very easy to do using PW API like this: $session->redirect($page->children->first()->url); in a Template File. 9. getField (Evolution) and getResourceField (Revolution): Inbuilt in PW $page and $pages variables as shown above. 10. GetParent: Inbuilt in PW $page and $pages variables. E.g. $page->parent. 11. getPage: PW has inbuilt pagination as part of the Core (Pagination Markup Module). See this article for a quick tutorial. 12. UltimateParent: Inbuilt in PW API as rootParent. 13. if (Revolution): Use vanilla PHP with PW variable and selectors in Template Files. 14. VersionX (Revolution): Versioning for text-based fields is coming in PW 2.4 (release date summer 2013). Support for maintaining separate draft and live versions coming in PW 2.5 (Winter 2013/2014). Currently, there is also the Module Version Control for Text Fields. 15. getRelated (Revolution): No out-of-the-box Module for this. Has been previously accomplished using PW API in various ways. Have a look in the forums. 16. importX (Revolution): Import Pages CSV Module. 17. phpThumbOf: Thumbnail functionality is inbuilt in PW. There is also the Module Thumbnails that further extends this functionality. 18. getValue and getValues (Revolution): Inbuilt in PW. You can get the value of any Page using PW API - $page and $pages. 19. getFeed (Revolution): RSS Feed Loader Module. 20. MIGX (Revolution): Repeater Module which is part of the PW Core. It is not installed by default. You will need to do that yourself. For more info see this tutorial. 21. Articles (Revolution): See the Blog Profile Module. 22. NewsPublisher (Revolution): See below under Plugins. Examples MODX Ditto [!Ditto? &parents=`5`&extenders=`summary` &tpl=`tplBlog` &orderBy=`createdon ASC`&display=`6` &truncText=`Continue Reading This Article` !] PW equivalent $items = $pages->get(5)->children("sort=date,limit=6"); foreach ($items as $item) { echo $item->title; echo $item->summary;//etc. } //this assumes you have a Field called summary on that Page The first line in the above gives you all information about the 6 child Pages of the Page with ID #5. It returns an array. In other words, a basket of various documents containing all the info about those documents. Next, you traverse the array using foreach. In layman terms, you rummage through the basket picking goodies! In order to wrap HTML around the code output, we do it like this instead (there’s other ways to do it as well!) echo "<ul class='articles'>"; foreach($pages->get(5)->children("sort=date,limit=6") as $item) { echo "<li><p><a href='{$item->url}'>{$item->title}</a><br /> <span class='summary'>{$item->summary}</span></p></li>"; } echo "</ul>"; In this example, we have asked PW to grab the child Pages directly within the foreach rather than creating a variable $items first. MODX getResources // Output a list of child Resources of the current Resource, using the 'myRowTpl' chunk: [[!getResources? &parents=`[[*id]]` &tpl=`myRowTpl`]] PW equivalent echo "<ul>"; foreach ($page->children as $child) { echo "<li><a href='{$child->url}'>{$child->title}</a></li>"; } echo "</ul>"; //You might want to limit the number of child Pages you are getting if they are many! MODX getResources // Output the top 5 latest published Resources beneath the Resource with ID '5', with tpl 'blogPost': [[!getResources? &parents=`5` &limit=`5` &tpl=`blogPost` &includeContent=`1`]] PW equivalent echo "<h3>Latest Posts</h3>"; $posts = $pages->get(5)->children("limit=5"); foreach ($posts as $post) { echo $post->body; } c. Modules 1. Batcher and Docmanager (Revolution): Batcher Module (covers most equivalent functions). 2. DocFinder (Evolution): Inbuilt in PW default install. d. Plugins 1. QuickManager (Evolution): Several Modules can do this, i.e., Fredi, Page Frontend Edit and Inline Editor Modules. 2. ManagerManager (Evolution): Same functionality can be achieved using Templates, Access Control and the Modules Page Edit Field Permission, Page Edit Per User and Page Edit Per Role. e. Chunks See this example. Btw, the PW Cheat Sheet is you best friend... Hope this has been helpful! /kongondo1 point
-
Hi, during work on some own modules (frontend content manager, frontend users) I noticed my need of a helper module. Template2Form (working title) is a module to build a form based on fields get from a page object or a template file (tmp fake page object). During build process each field could be hooked in to modify it. Also it's possible to modifiy form, submit button and form fields via function params. It's my first (basic / dev state) module I post here... If it will be useable I have to clean up and comment the code well... template2form class <?php /** * Processwire 'template2form' module * * template2form - generate form from page / template fields * * @author pwFoo * @since 2014-07-18 * * ProcessWire 2.x * Copyright (C) 2011 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://www.processwire.com * http://www.ryancramer.com */ class Template2Form extends WireData implements Module { /** * @var object $form generated form object */ public $form; /** * @var array $option multidimensional array with options */ private $option; /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * @return array */ public static function getModuleInfo() { return array( 'title' => 'Template2Form', 'summary' => 'Generate form from template fields', 'version' => '0.0.1', ); } /** * Default module and form options * @var array $defaultOptions static mutlidimensional array with default options */ public static $defaultOptions = array( 'page' => null, 'template' => null, 'prefillFormFields' => null, 'jquery' => null, 'form' => array('method' => 'post', 'action' => '', 'id' => 'login', 'name' => 'login'), 'formSubmit' => array('id' => 'submit', 'name' => 'submit', 'value' => 'Submit'), 'formFields' => null, ); public function init() { $this->addHookAfter('Template2Form::buildField', $this, 'hookingFormField', array('priority'=>20)); } /** * Set / merge module and form options * @param array $options Array with given options * @return null */ private function setOptions (array $options = null) { if($options != null && is_array($options)) { $this->option = array_replace_recursive(self::$defaultOptions, $options); // Use template instead of page if given if ($this->option['template] !== null) { $this->option['page'] = $this->fakePage($this->option['template']); } // No template or page? Use current page... elseif ($this->option['template'] === null) { $this->option['page'] = $this->page; } if ($this->option['jquery']) { $this->modules->get('JqueryCore'); } } else { $this->option = self::$defaultOptions; } } /** * Generate the form object * @param array $options Set of optional and needed settings * @return object Generated form */ public function getForm (array $options = null) { $this->setOptions($options); $this->form = $this->buildForm (); return $this->form; } /** * Generate the form object from given fields * @return object Generated form */ private function buildForm () { $form = $this->modules->get('InputfieldForm'); $form = $this->setFormAttr($form); // Get fields to build the form $fields = $this->templates->get($this->option['page']->template)->fields; foreach ($fields as $field) { $f = $this->buildField ($field); // Get Inputfield object if ($f !== NULL) $form->append($f); // Remove NULLed fields from from... } $form->append($this->addSubmitButton()); return $form; } /** * Set form attributes and return the object * @param object $form * @return object Form with added attributes */ protected function ___setFormAttr($form) { $form->id = $this->option['form']['id']; $form->name = $this->option['form']['name']; $form->action = $this->option['form']['action']; $form->method = $this->option['form']['method']; return $form; } /** * Generate Inputfield object from given field object * @param object $field Page field object * @return object */ protected function ___buildField ($field) { return $field->getInputfield($this->option['page']); } /** * Modify the current field object by hook in after buildField function * @param object $event */ protected function ___hookingFormField ($event) { $field = $event->return; $hook = $this->option['formFields'][$field->name]; // Remove selected field... if ($hook['remove'] == true) { $event->return = NULL; } // prefill form fields from page value... elseif ($this->option['prefillFormFields'] && $event->page->get($field->name)) { $hook['set']['value'] = $event->page->get($field->name); } if (!isset($hook)) return; // nothing to do with this field... // Set form field values... elseif (is_array($hook['set'])) { foreach ($hook['set'] as $key => $value) { $field->set($key, $value); } $event->return = $field; } } /** * Build the form submit button * @return object form submit Inputfield */ protected function ___addSubmitButton() { $btn = $this->modules->get('InputfieldSubmit'); $btn->attr('id', $this->option['formSubmit']['id']); $btn->attr('name', $this->option['formSubmit']['name']); $btn->attr('value', $this->option['formSubmit']['value']); return $btn; } /** * Rendering the current form * @return string Rendered form as html code */ public function ___formRender() { return $this->form->render(); } /** * Process form data if send * @return object Processed form data */ public function ___formProcess() { $submit = $this->option['formSubmit']['id']; if(!$this->input->post->$submit) return NULL; // form NOT submitted... $processedForm = $this->form->processInput($this->input->post); // form api process form values if(!$this->form->getErrors()) return $processedForm; // form processed: OK else return false; // form send with errors } /** * Make fake page and assign needed template * @param string $tpl Template to assign * @return object Generated fake page to work with */ private function fakePage($tpl) { $fakePage = new Page(); $fakePage->template = $tpl; return $fakePage; } /** * jsConfig settings needed by wysiwyg editor * @return string Basic JavaScript config */ public function ___jsConfig () { $jsConfig = $this->config->js(); $jsConfig['debug'] = $this->config->debug; $jsConfig['urls'] = array( 'root' => $this->config->urls->root, 'admin' => $this->config->urls->admin, 'modules' => $this->config->urls->modules, 'core' => $this->config->urls->core, 'files' => $this->config->urls->files, 'templates' => $this->config->urls->templates, 'adminTemplates' => $this->config->urls->adminTemplates, ); return '<script type="text/javascript">var config = ' . json_encode($jsConfig) . '</script>'; } } Usage examples $t2f = $modules->get('Template2Form'); // Remove field 'headline' and 'body' from form $hookFormFields['headline'] = array('remove' => true); $hookFormFields['body'] = array('remove' => true); // Set / Overwrite field attributes / values like you could do with form api $hookFormFields['title'] = array('set' => array('value' => 'CustomTitle...', 'type' => 'password')); $hookFormFields['summary'] = array('set' => array('value' => 'My overwritten summary...')); // Overwrite submit button attributes (default: id, name, value) $hookFormSubmit = array('value' => 'Speichern'); /* * Build the multidemensional array * page (object) or template (string) -- to build the form from * prefillFormFields -- prefill fields (for example to build a frontend edit page * jquery -- Load JqueryCore module (during getForm() call) * form -- set form attributes / values * formFields -- array to set field values / attributes, take a look at form api examples * formSubmit -- set form submit button attributes / values */ $formOptions = array('page' => $page, 'template' => null, 'prefillFormFields' => true, 'jquery' => true 'formFields' => $hookFormFields, 'formSubmit' => $hookFormSubmit); // Generate the form and set options above $t2f->getForm($formOptions); // process form and return processed form date $process = $t2f->formProcess(); if ($process === NULL) // form not sent elseif ($process === false) // form sent, but with errors elseif ($process == true) // form sent without errors // Render form... $form = $t2f->formRender(); echo '<html><head>'; // jsConfig needed by ckeditor echo $t2f->jsConfig() . "\n"; // outpunt needed scripts for inputfield modules, ... foreach ($config->scripts as $file) { echo "<script type='text/javascript' src='$file'></script>\n"; } foreach ($config->styles as $file) { echo "<link type='text/css' href='$file' rel='stylesheet' />\n"; } echo '</head><body>'; echo $form; // output form echo '</body></html>';1 point
-
1 point
-
You should put that on a T-Shirt. Make it a new campaign. I mean, those Queries need saving before they go extinct!1 point
-
1. https://processwire.com/talk/topic/2394-how-to-present-your-module/ http://processwire.com/api/modules/ https://processwire.com/talk/topic/741-a-guideline-for-module-naming/ 2. GitHub (preferred; maybe even required now but Ryan will confirm )1 point
-
Damn it is embarrassing that I felt the need to Like that suggestion of Joss'. I used to be fine on a 15" laptop running 1920x1200. Seems like 40 really is the beginning of the end when it comes to small things and low light1 point
-
The endless link appending is because of the dot ./kontakt/ ... remove the dot and save a query.1 point
-
1 point
-
I'm a dinosaur. I use Photoshop for all my prototyping and design (although this is becoming more of a problem now that everything is responsive). For HTML/CSS, I hate things like SASS, Bootstrap, grids, frameworks, etc. I like being as close to the raw code as possible and having full control over everything I do. I find things like SASS just get in the way and it's just more stuff I have to learn. I'd rather just learn and know actual HTML & CSS to the highest level possible. I realize I could probably save time and make my life easier if I picked up a framework, but... ugh, I'm just not in that headspace. However, I do love jQuery and leverage that. Also, on the back-end of things I obviously don't do things from scratch and use CMS/CMF's like PW, ModX, etc. My typical workflow: 1. Client Engagement / Project Initiation stuff 2. Client fills out Creative Brief, we skype and discuss the brief 3. I create a 100% fully realized design for the home page, standard content page and any special pages. 4. I present the above designs as background PNG's in a basic HTML page so clients can review in their browser. This way the client sees in their browser exactly what they'll see once the site is built. Of course none of the links, etc. work, being a static image. 5. Revise designs according to feedback. Once all design work is signed off on, I then proceed with production. 6. Production stuff... 7. SEO / SocialMedia / Rep Marketing stuff... 8. Revisions, final tasks, backups, etc. 9. Project wrap-up I realize steps 3, 4 and 5 are seriously flawed this day and age. Especially with responsive design. I need to alter my front-end design workflow, but I've been so consumed by this thing called ProcessWire that's taking up all my learning time1 point
-
Yes we can still keep a copy of fireworks for the very reason that the Creative cloud was not around before. What would happen today if Adobe discontinued one of their products? Would I need to keep paying a subscription to keep using a non updated software if they even kept it in the creative Cloud? Or they could just remove it from the Creative Cloud totally with no possibility to use it again. I think at the very least Adobe should have open sourced Fireworks to let others carry on developing it.1 point
-
I already said I liked it on Twitter. Teeny-tiny thing about the icons (I'm glad I'm not the last person on earth who uses icon fonts, BTW) – you could make the icon font icons a wee bit nicer for screen readers if you replace i.e. <i class="icon-search"></i> with <span class="icon-search" aria-hidden="true"></span> The i element is “text in an alternate voice” in HTML5, I'm not sure if screen readers react on that. The aria-hidden makes screen readers not read out the glyph used for the icon. However, if you use aria-hidden, you should also add a fallback text for screen readers to actually read … <span class="icon-search" aria-hidden="true"></span><span class="screen-reader-text">Search</span> … and hide that for visual browsers. While I'm poking at the search, why not use type="search" for the input? Also, the search input is missing a label (again, just for screen readers, and it should probably be hidden for visual browsers as well.)1 point
-
1 point
-
hi siteaddict, welcome to processwire! i'm sorry that i can't give you an exact answer, but maybe this thread helps you: https://processwire.com/talk/topic/5941-state-and-cities/ good luck and have fun with processwire1 point
-
WoW, what can I say, pw production band ? Great design/pics as ever.1 point
-
Yes lots to study : a) double quotes forces PHP to evaluate the string (even though it might not be needed) b) a string between single quotes is not evaluated. c) parsing a variable between strings takes more memory than concatenate a variable. So this should work: echo '<div id="button2" class="button_style" onclick="location.href=\'page2.html\';" style="cursor: pointer;">product</div>'; Edit: Tried it and the above works, even the onclick part Tried also the other way around = starting with echo "<div id= . . . and escaping with \'page2.html\' obviously the button appeared but the onclick part failed.1 point
-
You need to study more, escaping the quotes comes explained in the first chapter of any php book1 point
-
Here an updated / reworked module version... <?php /** * Processwire 'FormHelper' module * * Generate forms from pages, templates or input data * * @author pwFoo * @since 2014-09-13 * * ProcessWire 2.x * Copyright (C) 2011 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://www.processwire.com * http://www.ryancramer.com */ class FormHelper extends WireData implements Module { protected $form; protected $submitBtn; protected $cfg = array( 'page' => null, 'template' => null, 'clearFormValues' => null, 'jquery' => null, 'jsconfig' => null, // form default settings 'form' => array( 'module' => 'InputfieldForm', 'vars' => array('method' => 'post', 'action' => ''), 'attr' => array('id+name' => 'formhelper'), ), 'submit' => array( 'module' => 'InputfieldSubmit', 'attr' => array ('id' => 'submit', 'name' => 'submit', 'value' => 'Submit'), ), 'fields' => null, /* * 'fields' => array( * 'username' => array( * 'module' => 'InputfieldText', * 'position' => 'insertBefore:password', // "insert method" [":" "reference field"] * 'vars' => array('name' => 'username', 'label' => 'Username', 'required' => true), // var "name" required! * 'attr' => array('id+name' => 'username'), * ), * ), */ ); /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * @return array */ public static function getModuleInfo() { return array( 'title' => 'FormHelper', 'summary' => 'Generate and process forms from page / template fields or given field parameters', 'version' => '0.0.2', ); } protected function setCfg ($arr, $reset = null) { if ($reset === null) { $this->cfg = array_replace_recursive($this->cfg, $arr); } else { $this->cfg = $arr; } } /** * Generate the form object from given fields * @return object Generated form */ public function ___createForm (array $cfg = null, $reset = null) { // merge or overwrite default config if ($cfg !== null) $this->setCfg($cfg, $reset); // create form field / wrapper $this->form = $this->setObj($this->cfg['form']); // Get inputfields from page object or given template if ($this->cfg['page'] || $this->cfg['template']) $this->getFormInputfields(); // create or merge form with given field data array if ($this->cfg['fields'] !== null && is_array($this->cfg['fields'])) $this->createFormFields(); // add submit button $this->submitBtn = $this->setObj($this->cfg['submit']); $this->form->add($this->submitBtn); return $this->form; } /** * ToDo: implement method / field positioning ? */ public function formField ($field, $method = 'add', $posRefField = null) { $field = $this->prepareField($field); $this->form->$method($field); } /** * */ protected function ___prepareField($field) { if(in_array($field->name, $this->cfg['skipFields'])) return null; // remove field if ($this->cfg['clearFormValues']) $field->value = null; // set value to empty return $field; } /** * Generate inputfields from given page object fields * @return object Generated field */ protected function getFormInputfields () { if ($this->cfg['template'] && !$this->cfg['page']) { $this->cfg['page'] = $this->fakePage($this->cfg['template']); } foreach ($this->cfg['page']->getInputfields() as $field) { $this->formField($field); } } /** * Generate form fields based on given data array * @return object Generated field */ protected function createFormFields() { foreach ($this->cfg['fields'] as $formField) { // Update form field if exists if ($exists = $this->form->get($formField['vars']['name'])) { $this->setObjValues($exists, $formField); } // Doesn't exist? Create and add it to form... else { $field = $this->setObj($formField); $this->formField($field); } } } /** * Rendering the current form * @return string Rendered form as html code */ public function ___render() { return $this->form->render(); } /** * Process form data if send * @return object Processed form data */ public function ___formProcess() { $submit = $this->submitBtn->get('name'); if(!$this->input->post->$submit) return NULL; // form NOT submitted... $processedForm = $this->form->processInput($this->input->post); // form api process form values if(!$this->form->getErrors()) return $processedForm; // form processed: OK else return false; // form send with errors } /** * Generate a field / form object * @param array $arr Needed values to create the object * @return object Generated field object */ private function setObj($arr) { $obj = $this->modules->get($arr['module']); $this->setObjValues($obj, $arr); return $obj; } /** * Update form / field variables and values * @param object $obj field object by reference * @param array $arr field variables/ properties and attributes */ private function setObjValues(&$obj, $arr) { if (is_array($arr['vars'])) { foreach ($arr['vars'] as $key => $value) { $obj->set($key, $value); } } elseif (is_array($arr['attr'])) { foreach ($arr['attr'] as $key => $value) { $obj->set($key, $value); } } } /** * Make fake page and assign needed template * @param string $tpl Template to assign * @return object Generated fake page to work with */ private function fakePage($tpl) { $fakePage = new Page(); $fakePage->template = $tpl; return $fakePage; } /** * jsConfig settings needed by wysiwyg editor * @return string Basic JavaScript config */ public function ___jsConfig () { $jsConfig = $this->config->js(); $jsConfig['debug'] = $this->config->debug; $jsConfig['urls'] = array( 'root' => $this->config->urls->root, 'admin' => $this->config->urls->admin, 'modules' => $this->config->urls->modules, 'core' => $this->config->urls->core, 'files' => $this->config->urls->files, 'templates' => $this->config->urls->templates, 'adminTemplates' => $this->config->urls->adminTemplates, ); return '<script type="text/javascript">var config = ' . json_encode($jsConfig) . '</script>'; } } Some features (jquery, jsconfig, ...) missing, but it works with a simple page / template... My testing template code (also with form field overwrite (for example field username). <?php $fh = $modules->get('FormHelper'); $formFields['username'] = array( 'module' => 'InputfieldText', 'vars' => array('name' => 'username', 'label' => 'Username123', 'required' => true), 'attr' => array('id+name' => 'username'), ); $fh->createForm(array('template' => 'register', 'fields' => $formFields)); // process form $process = $fh->formProcess(); if ($process === NULL) { echo "Nicht abgeschickt<br /> <br />"; } elseif ($process == true) { echo "Abgeschickt, ohne Fehler<br /> <br />"; } elseif ($process === false) { echo "Abgeschickt, mit Fehlern<br /> <br />"; } $form = $fh->render(); // returns rendered form echo '<html><head>'; // jsConfig needed by wysiwyg editors echo $fh->jsConfig() . "\n"; // outpunt needed scripts for inputfield modules, ... foreach ($config->scripts as $file) { echo "<script type='text/javascript' src='$file'></script>\n"; } foreach ($config->styles as $file) { echo "<link type='text/css' href='$file' rel='stylesheet' />\n"; } echo '</head><body>'; echo $form; echo '</body></html>'; Be careful... don't use "$fields" as variable to build the form fields data array. I should change the array key 'fields' again because it lead to use $fields as variable to build the sub array... UPDATE Latest version also fixed a bug during set field properties / attributes...1 point
-
This site is also multilingual. I did it like arjen suggested. Created a _init.php file in the templates folder with $config->urls->root = "/" and then I've uncommented the line (50) on config.php : $config->prependTemplateFile = '_init.php'; That way, this code is prepended to every template and so it's executed before any code on the templates.1 point
-
Building upon what you described in your original post and what Joss said... Templates and Relationships - bars (bars.php) - bar1 (bar.php) - bar2 (bar.php) - barN (bar.php) - chocolate types (chocolate_types.php) - chocolate_type1 (chocolate_type.php) - chocolate_type2 (chocolate_type.php) - chocolate_typeN (chocolate_type.php) - confectioners (confectioners.php) - confectioner1 (confectioner.php) - confectioner2 (confectioner.php) - confectionerN (confectioner.php) - shops (shops.php) - shop1 (shop.php) - shop2 (shop.php) - shopN (shop.php) - countries (countries.php) - country1 (country.php) - country2 (country.php) - countryN (country.php) Fields - bars (page field, multi-select asm or whatever is the most appropriate given amount of data) - chocolate_type (page field, regular select or whatever makes the most sense; i'm assuming each bar has one chocolate type) - confectioners field (page field, multi-select asm or whatever is the most appropriate given amount of data) - shops field (page field, multi-select asm or whatever is the most appropriate given amount of data) - country field (page field, regular select or whatever makes the most sense; i'm assuming each confectioner has one country) Templates w/ Fields - bar.php - title - (etc) - chocolate_type - chocolate_type.php - title - (etc) - confectioner.php - title - (etc) - bars - country - shop.php - title - (etc) - bars - country.php - title - (etc) Example Code Per Template - bars.php list bars: foreach($page->children as $bar) - chocolate_types.php list chocolate types: foreach($page->children as $chocolate_type) - confectioners.php list confectioners: foreach($page->children as $confectioner) - shops.php list shops: foreach($page->children as $shop) - countries.php list countries: foreach($page->children as $country) - chocolate_type.php list bars that have the chocolate type: $bars = $pages->find("parent=/bars/, template=bar, chocolate_type={$page}"); foreach($bars as $bar) - confectioner.php list bars: foreach($page->bars as $bar) - shop.php list bars: foreach($page->bars as $bar) - country.php list confectioners in the country: $confectioners = $pages->find("parent=/confectioners/, template=confectioner, country={$page}");1 point
-
Arjen: Neat and clean. Thanks, it solved the problem!1 point
-
You should rewrite the url to: $config->urls->root = '/'; Load this as early as possible in your templates, so your _init.php might be a good location. I use this all the time when storing websites in folders.1 point
-
We have Area51. Heinz57. And the Fibonacci Sequence. We now have Post144. BTW: You like fish? I like Turtles. Yes. I said Turtles.1 point
-
I'd gladly accept the pull request. But I totally don't understand why output formatting is off in the first place. Some general admin thing? Would make sense, but then I think it wouldn't be the best idea to simply turn it on. Perhaps there is a reason for setting it to off? Does anyone know why? Btw: I am thinking of building a version where the rows get rendered in an Iframe (pretty much like Form Builder does), so we have a more sandboxed solution. Not quite sure about the additional work needed though.1 point
-
I think it makes sense to keep the direct output, since more advanced developers will most probably start with a blank state anyway.1 point
-
Updating Blog version 1 to Blog version 2 Note: some paths have changed. You will have to update such paths in your template files. Please see point #10 below 1. Log in as a superuser. 2. Backup your site! (For good measure). 3. Update Blog version 1 to version 2. Grab version 2 in the previous post OR from Blog's dev branch in GitHub 4. Paste the contents of the attached update script (blog-upgrade-version-1-to-2.txt) at the very top of one of your site’s template files. This script will create a ‘settings’ page under ‘blog’. The fields in the pages ‘blog’ and ‘posts’ will now reside in this new settings page. Their existing data will be copied over to the settings page. There will be no data loss. In addition, one extra field called blog_small will be created and added to the settings page If you want to enable the Auto-publish/unpublish feature FIRST install the module SchedulePages. Second, uncomment line #41 in the update script AND comment out line #40 of the script before copying and pasting. Save the template file. 5. View a page that uses the template associated with the template file in #4. 6. A success message will be displayed if all went OK. 7. Undo the changes to the template file in #4. Save. 8. Go back to your site’s admin to confirm things went fine, in particular: Check that a ‘settings’ page was created under ‘blog’ View ProcessBlog’s module configuration settings page (admin > modules > blog) by clicking on its settings button. You should see a message about Blog already fully installed Visit Blog Dashboard to confirm things went OK. If you enabled the Auto-publish/unpublish feature above, you should see two extra date fields in the Quick post dashboard (‘Publish from’ and ‘Publish until’). Similarly, edit one of your Blog’s posts pages. You should see these two date fields as well at the very top of the page. 9. Manually remove the now redundant fields in the templates ‘blog’ and ‘blog-posts’. Template 'blog': fields to remove: Blog Title - 'blog_headline' Blog Tagline - 'blog_summary' Footer - 'blog_note' Quantity of posts to show on blog homepage - 'blog_quantity' Template 'blog-posts': fields to remove: Posts truncate length - 'blog_quantity'. This will now become blog_small in settings page 10. Edit your template files paths that pointed to these fields you’ve just removed to now point to their counterparts in the settings page, e.g. $pages->get('/blog/settings/')->blog_quantity; That's it. You are updated. If you want to, you can now even rename your Blog pages to whatever you want (within reason of course ).... Enjoy! blog-upgrade-version-1-to-2.txt1 point
-
A few updates in response to the PDF that was posted earlier. More to come, but this is a start. Currently these are just on dev, but will be merged to master soon. The main README file has been updated with a link to the HTML version at the very top. I honestly think including a README.html file in the core itself is bad form because it reveals exactly what software is running the site. Some might have noticed our README files are generally blocked from http access (by the .htaccess file) for this very reason. So I think putting a link to the HTML version of the document at the top of the Markdown file is a good compromise. The default site profile has been updated with its own README file and separately hosted HTML version: Introduction to the default site profile, which goes in depth in explaining exactly how the site profile works. The template files have also been updated, telling the user to see README.txt for more information (though not sure that's really necessary).1 point
-
1 point
-
1 point
-
Code before talk. With 2.5.0 released Friday, and 2.5.1 dev released today, there's been a lot of code.1 point
-
Hey guys, Recently I saw the module https://github.com/owzim/TextformatterParsedown It keeps the parsedown in the directory. If we could make use of the composer installer via the module I have created it will help people to get up to dated the dependencies than the project maintainer doing the update. I wish if processwire could make use of the composer functionality in the core.1 point
-
Hi Beluga, Thanks for sharing that link. Very interesting. I've made a basic PM tool using PW, I'll be expanding it little more for a client's project. I'll post it here once it's ready. For now it's just a simple task management system. If anyone's interested, feel free to contact me, I've a demo online which I'm using to manage my company's projects. Have a great day!1 point
-
Hi, everyone! I would be glad to become a part of this lovely community! Greetings from Lithuania! Here is my problem. I am translating ProcessWire to Lithuanian language and I need TinyMCE to have the ability to be translated too. In my admin panel there is a guideline "If your language isn't there, ask us to add it. We will if TinyMCE has it: http://www.tinymce.com/i18n", so I am asking, maybe you could add LT language to the list of possible in the next release? Best regards, Jim.1 point
-
See http://php.net to see what all you can do in ProcessWire For conditionals: http://www.php.net/manual/en/control-structures.if.php In PW short way is for example echo $pages->get("title|headline"); saying if title has value output title, otherwise get headline1 point