Leaderboard
Popular Content
Showing content with the highest reputation on 09/02/2013 in all areas
-
Two days ago, an idea about a new admin theme came to my mind. Some hours later, I've crafted a first concept in Adobe Fireworks.... The look and feel of the admin is important Two months ago, I've introduced some teachers into ProcessWire. They were none-technically people. At the end, they knew how to use the admin panel to create content or update a gallery on their new page. However at some points, they got confused with parts of the admin theme -beside the problems with our concept on how to use fields and templates for creating content. I think one factor why Wordpress became so large, was the great Adminpanel. It works well and easy (as long as you have a blog and not a twenty-plugins-for-text-pages-site). Editing content on a daily basis is the main task of my customer. I've to take this aspect serious. Problems I wanted to solve Have the page tree always visible. If I do not click the right link, it will be closed after I've finished editing my site More visuals like icons. Simplify some workflows. Creating 3 or 4 pages can result in multiple unnecessary clicks. More focus on important links like the tabs. Guide my customer through some action. Help them to repeat simple tasks. The concept First: Nothing is perfect and its not possible to find one single solution for everything. This was just done in a couple of hours and it's only the first iteration. Quick action button Next to the ProcessWire logo is the quick "Quick Actions" button. It should be possible, to configure it like: "Create a new Page with Template X with page Y as a parent". Use it for skyscrapers, news or galleries. (Yes i know, the arrow is pointing upwards. This is wrong) Two column layout The page tree is always visible (as long as we are in the pages view). It can be navigated as the normal page-tree. If you click "edit" it will become highlighted. Every action that would take you to a new page, would be displayed in the other half of the monitor. Speaking of a "half monitor" - I think that most people use a screen resolution of atleast 1300px. The sidebar should take up to 1/3 of this. On smaller screens, it will become hidden by default or we just simply step back to single pages for each view. If the content is to long, the sidebar becomes scrollable. Page tree I like the Template Decorator made by mindplay.dk. It fits the concept well with black outline icons for every type of template. The same icons could be used in the Quick action menu. I'm note sure what to do with the "move" action. To Do list Think more about the behavior of the elements. Design the modules view. Rework the search and the top menu. Options to "brand" the panel for agencies while keeping the ProcessWire logos. What happens if we are on mobile (small screen) devices? Listen to your feedback.11 points
-
Nice job Philipp, I like where you are going with this. Thanks for putting your time and skills towards this. Having a new default admin theme is something I think we need to approach soon, and contributions like this are very much appreciated. I also think your work here is nice to look at and very well designed. With regards to an always visible page tree: not showing the page tree when in the page editor is very much a conscious decision. I recognize there are benefits and drawbacks and that it's a compromise either way. Here's the thinking of why we currently compromise on the side of not showing it: The default admin theme needed to be something that could scale near infinitely, and delegating the page tree to a sidebar introduces a lot of natural limitations (though none that scrollbars can't solve, but I'm not a fan of them). Another goal was to keep the user focused on the page they are editing by having the browse and edit states be very separate things. Lastly was the issue of overhead: generating a page tree involves a lot of work, and can contribute to making the admin feel slow… especially if having to generate it for every page edit. (Though this may be something caching could solve, but it could be tricky to develop: clearing such a cache after each page save might defeat the purpose). I did actually test out both SilverStripe and MODX before developing ProcessWire–I wasn't pleased with their page trees and really wanted to differentiate ourselves from that. Though your design here for the page tree does do that–it looks a whole lot better than what's in other systems. Those are some of the reasons why we'd decided not to show the page tree when in the page editor. But I recognize there are some real benefits: I like the possibility of being able to quickly jump between pages when needing to make edits to multiple pages or needing to add a bunch of pages. I also like the aspect of seeing where I am in the tree… While the breadcrumb trail accomplishes it, the tree can reinforce it. But these benefits were not enough to outweigh the benefits of not showing it. Still, if there is great demand, or if people would prefer the option, I'd be supportive of it as an option in the default admin theme. Though do wonder if a full-width, click-to-reveal panel at the top of the screen would better solve the scalability aspect? Whether sidebar or top-panel, if these things open only when hovered or clicked, we could solve the overhead problem by just doing it with ajax. For the Quick-Add button, I believe we could easily support this on any templates that have family settings defining a single required parent. When templates are configured that way, they could have a checkbox that says "Add to quick-action list?" or something along those lines. Keep up the great work. I look forward to seeing more.6 points
-
Earlier today I was thinking of a use/case situation where I might use parenting or page fields to tie together some related pages. The better approach was page fields and really the only reason I was even trying to make it work with parenting is that it would be easier to explain to a client how to set it up. This is a case where a client-oriented admin interface could make it easy to select the related pages and declare the relationship but hide the actual details of how that relationship is expressed in PW. In my pre-PW work I've done a lot of custom admin pages for clients to use. It really pays to keep these very focused on application-specific work flow, terminology, etc. I don't expect clients to accept the level of abstraction necessary to work directly with the PW data. The admin pages provided by core should be a tech tool, guaranteed to be scalable and capable of accessing anything any application might have. Sure, there's room for improvement but what about putting that effort into easing the task of constructing a more focused and mediated admin interface for clients to use. I haven't looked deeply at how the admin pages work now but given the modular way things tend to be done in PW I'd think we could do something to streamline the building of custom admin pages. Sort of an admin construction kit. Let the client deal with "skyscrapers" and "cities" rather than "pages" even though underneath, they are all PW pages. Reuse the basic underlying CRUD while adding application specific prompting and tools to help the user with the more focused task of working on a city, skyscraper, category, etc. Build a custom interface where clients can do their routine tasks easily. if they end up with an odbball situation beyond the scope of what you built for them you can always talk them through using the standard admin interface, and if that becomes a habit you extend their custom interface. Personally, I don't think a single admin interface is ever going to be optimal for both programmer and client. Those are different audiences with different needs. I'd be wary of anything that compromises the ability of the standard admin pages to deal with huge amounts of data etc.4 points
-
To justify the optional sidebar: Screens under 1200px will not see the sidebar. It will be hidden by default. I've set the first offset margin to 15px and then increase the margin by 20px each level. On a 1280px Screen with 1/3 sidebar I get around 425px. On a 1920px Screen (24" HD Office) I will have 640px for the sidebar. The "problem" are different lenghts for the text + the edit|view|new buttons. Question: How many sublevels do you usually have? I like that aspect. In the next version of the concept I've stripped down some icons. I'm using them for arrows and the template type of a page. I think, it's the tiniest way to display the "type" of template of a page.If not, my customer just thinks of pages and not of galeries,blog posts, news, products,... The top bar is now white. I've chosen the pink/magenta color for everything that has an action, the blue colorto indicate things. The font size also went done from 18px to 16px and the overall look is now a little bit more compact. The second screenshot demonstrates a 1280px window size. This would be a great start. Especially with the theme switcher for the upcomming versions. We could quick build a custom view for a client. Another thing to the "Admin Kit". Maybe the admin-themes can get some sort of an option page where we can disable things like the sidebar. Not sure about this one...2 points
-
2 points
-
That function is now in core for use with WireArrays. This isn't only for pages. Just as an example with a stack of images: $fs = new WireArray(); $pa = $pages->find("template=image, image.count>0"); foreach($pa as $p){ $fs->add($p->image); } $f = $fs->findRandomTimed(1); echo $f->first2 points
-
The admin theme files are a combination of HTML/PHP, CSS, JS files and images. For the most part, it is no different from what you would create in your own site files (in /site/templates/). By default, the admin theme files are located in this directory: /wire/templates-admin/ STEP 1: To create a new admin theme, you would copy the default admin-templates directory (/wire/templates-admin/) to here: /site/templates-admin/ When ProcessWire sees /site/templates-admin/, it will use it instead of the default one. STEP 2: Now you can modify any of those files in /site/templates-admin/ and your changes should be reflected in the admin control panel. STEP 3: To distribute it to other people, you would just zip up the dir and then anyone else can unzip it to /site/templates-admin/ and have it work. I will be glad to setup a directory of admin themes on the site if anyone else decides to make one. That is all there is too it. But here are some other details and recommendations you may find helpful: MORE DETAILS: Why not just edit the files in /wire/templates-admin/ ? You certainly could do this, but you should consider everything in /wire/ specific to ProcessWire, and everything in /site/ specific to your installation. If you were to modify the files in /wire/templates-admin/, then your changes would get overwritten every time you upgraded ProcessWire. Whereas, /site/templates-admin/ is not overwritten during upgrades. What if I only want to change stylesheets and images? If you only need to change stylesheets and images, then I would recommend having your /site/templates-admin/default.php just include the one in /wire/templates-admin/, i.e. /site/templates/default.php: <?php include("/wire/templates-admin/default.php"); And likewise for any other files in there that have markup that you don't want to modify. This includes notices.inc and debug.inc. You'll also see a controller.php file there, but that is already just a placeholder so no need to make any changes to it. What are all the files in ProcessWire's admin theme and what do they do? Files you can edit: debug.inc - An HTML/PHP file that is included when $config->debug is true. It outputs general debugging information in the admin. default.php - The main HTML/PHP container template. All admin output goes through this file. notices.inc - Generates the markup for admin messages and error notices that appear at the top of the screen. scripts/ - Directory containing jQuery/javascript files. scripts/main.js - Main jQuery/javascript file that is run on all admin pages. All this does currently is setup a few minor form interactions. styles/ - Directory containing CSS files/stylesheets styles/main.css - Initial layout and styling for the admin control panel. styles/reset.css - Resets all browser styles styles/ui.css - User interface override styles. This is the last stylesheet loaded so it can more easily modify styles that came before it as needed. styles/JqueryUI/ Directory containing jQuery UI specific stylesheets and images. You can use jQuery UI's themeroller for these if you prefer. http://bit.ly/eTVbDC styles/ie.css - Styles specific to IE styles/ie7.css - Styles specific to IE7 and below. Because we don't support those, this basically just turns off IE7 support. styles/images/ - Images used by any of the above stylesheets. Files you shouldn't bother editing: controller.php - This is just a placeholder that includes a controller in /wire/core/. You should leave this file as-is. install-head.inc - These HTML files are used by the installer. You can edit them, but ProcessWire will still use the one in /wire/templates-admin/ since they are only used before installation. As a result, you can delete them from your /site/templates-admin/ if you prefer. install-foot.inc - See above. scripts/install.js - See above. styles/install.css - See above. Modifying form widgets with jQuery UI Most of the form inputs in ProcessWire are based on a jQuery UI theme. It is located in this file /wire/templates-admin/styles/JqueryUI/JqueryUI.css (and the images directory below it). Like the other CSS files, that can be edited directly. But since this was originally built using JQuery UI's Themeroller, you can continue to modify it with that if you'd prefer. Here is a link to it with ProcessWire's admin styles already pre-populated: http://bit.ly/eTVbDC Copyrights and Logo You should leave existing copyright notices, links to processwire.com and the name ProcessWire in place. You should also add a notice indicating "[Admin theme name] copyright [your name]", i.e. "Widget admin theme copyright Gonzo Deutschdeung". We also prefer that you keep a copy of the ProcessWire logo somewhere in your design, but it's up to you. A photoshop file of the logo at high resolution is attached to this message. pw2-logos.zip1 point
-
Field dependencies are coming in ProcessWire 2.4, and I just wanted to give you guys a little preview of it. The development of this new feature is being sponsored by Avoine, the company where Antti works (he also specified how it should work). Field dependencies are basically just a way of saying that one field depends on another. It dictates which fields should be shown in a given context. In our case, it also gets into whether a field is required or not. This short video demonstrates how it works: (switch to the 720p and full screen version, as YouTube's default settings for this video make it impossible to see): // Edit @Adamkiss: Here's link for those on mobile: youtu.be/hqLs9YNYKMM The implementation here is done both client-side and server side. Javascript handles the showing/hiding of fields and the required vs. not required state changes. On the server side, it doesn't process any fields that aren't shown, and honors the required rules. A separate processing occurs both client side and server side, ensuring that the user can't make their own rules by manipulating the markup or post data. These field dependencies can be used with any Inputfield forms. That means you'll be able to use it not just in ProcessWire, but in FormBuilder, and via the API too. It's very simple to use from the API. All you have to do is specify a ProcessWire selector to either "showIf" or "requiredIf" to the Inputfield, and ProcessWire takes care of the rest: // show this field only if field 'subscribe' is checked $inputfield->showIf = "subscribe=1"; // show this field only if 'price > 0' and at least one category selected $inputfield->showIf = "price>0, categories.count>0"; // make this field required only if 'email' is populated $inputfield->required = true; $inputfield->requiredIf = "email!=''"; This feature will be in the 2.4 core (rather than as a separate module), so it will also be ready and available for things like module and field configuration screens.1 point
-
I have put together a very basic module for generating images from the pages of uploaded PDFs. It requires imagemagick, ghostscript, and the imagick pecl extension. It could easily be adapted to work without the imagick extension, but I usually like having exec disabled. At the moment it also requires a couple of specific custom fields: document_pdf (file) and document_thumb (image), both with "Maximum files allowed" set to "1". Obviously I will make these more generic, or add the fields on module install once this is closer to being released. There is some commented code that facilitates image resizing before upload to PW if that is what is wanted. I should also make these configurable module options. Currently I am using this for a searchable list of publications to generate a thumbnail of the cover to place with the description, PDF download link etc. I am planning on extending this a fair bit as I want to use it to generate image previews for each page of the PDF so I can use them in a "look inside" modal lightbox. These would all be stored in a standard images field. I think when I start generating images for all the pages I am going to run up against a speed problem. It could potentially take a few minutes to generate all the images for a large PDF. I was thinking of making use of lazycron, but I think I'd rather see some progress indicator. The other issue is if I use lazycron, then it is possible that someone may visit the site and go to use the look inside functionality before the images for all the pages are ready, so maybe this idea is out. Perhaps the best approach would be to hook into the PDF upload. Once the upload is complete, the module would start generating the images before the page is ever saved by the user. Would really appreciate any suggestions on how to set this up. Off the topic a little, but one other minor consideration in all this is RGB vs CMYK colorspace. If the user uploads an RGB PDF then everything is fine, but if someone uploads CMYK PDFs the colors are often terrible, but there is a tweak that can be made to imagemagick to fix it. Here is a good description of the problem and how to fix it: http://www.lassosoft.com/CMYK-Colour-Matching-with-ImageMagick Basically you need to add the command line option ''-dUseCIEColor'' to all of the GhostScript commands in the delegates.xml file, so that they now look like this: <delegate decode="eps" encode="ps" mode="bi" command='"gs" -q -dBATCH -dSAFER -dUseCIEColor -dMaxBitmap=500000000 -dNOPAUSE -dAlignToPixels=0 -sDEVICE="pswrite" -sOutputFile="%o" -f"%i"' /> Would anyone else make use of this module? Also, does anyone have any obvious suggestions for what I have so far. It's my first module, and I don't really have a handle on best practices yet. Thanks! PS I know convention is to attach module files, but this one is so short at the moment, it didn't seem worthwhile. <?php /** * ProcessWire ProcessPDFImageCreator * * Process PDF Image Creator creates images from PDFs. * * @copyright Copyright (c) 2013, Adrian Jones * */ class ProcessPDFImageCreator extends WireData implements Module { /** * Return information about this module (required) * * @return array * */ static public function getModuleInfo() { return array( 'title' => 'PDF Image Creator', 'summary' => 'Creates images from PDFs.', 'version' => 001, 'author' => 'Adrian Jones', 'singular' => true, 'autoload' => true ); } /** * Initialize the module and setup hook */ public function init() { $this->pages->addHookAfter('save', $this, 'createPdfImage'); } /** * If document_pdf field contains a PDF, generate an image from the first page. * * */ public function createPdfImage($event) { $page = $event->arguments[0]; if(count($page->document_pdf)>0){ $src = $page->document_pdf->first()->url; if(count($page->document_thumb)==0){ $pdf_filepath = $page->document_pdf->first()->filename . '[0]'; //the appended [0] refers to the first page of the PDF $jpg_filepath = str_replace('.pdf', '.jpg', $page->document_pdf->first()->filename); $resolution = 288; $im = new imagick(); $im->setOption("pdf:use-cropbox","true"); $im->setColorspace(Imagick::COLORSPACE_RGB); $im->setResolution($resolution,$resolution); $im->readImage($pdf_filepath); $geometry=$im->getImageGeometry(); $width = ceil($geometry['width'] / ($resolution/72)); $height = ceil($geometry['height'] / ($resolution/72)); $im->setImageFormat("jpg"); /*if($width>150){ $width = 150; $height = 0; } $im->scaleImage($width, $height);*/ $im->writeImage($jpg_filepath); $page->of(false); $page->document_thumb->add($jpg_filepath); $page->document_thumb->first()->description = $page->title . ' PDF thumbnail'; $page->save(); } } } }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
-
I found (after 2-3 Projects using PW) that it's a good technique to use templates in a way I think hasn't been thought of yet really by some. (Although the CMS we use at work for year, works this way.) I'm sure I'm maybe wrong and someone else is already doing something similar. But I wanted to share this for everybody, just to show alternative way of using the brillant system that PW is. Delegate Template approach I tend to do a setup like this: - I create a main.php with the main html markup, no includes. So the whole html structure is there. - I then create page templates in PW without a file associated. I just name them let's say: basic-page, blog-entry, news-entry... but there's no basic-page.php actually. - Then after creating the template I make it use the "main" as alternative under "Advanced" settings tab. So it's using the main.php as the template file. - This allows to use all templates having the same php master template "main.php" - Then I create a folder and call it something like "/site/templates/view/", in which I create the inc files for the different template types. So there would be a basic-page.inc, blog-entry.inc ... - Then in the main.php template file I use following code to delegate what .inc should be included depending on the name of the template the page requested has. Using the TemplateFile functions you can use the render method, and assign variables to give to the inc explicitly, or you could also use just regular php include() technic. <?php /* * template views depending on template name * using TemplateFile method of PW */ // delegate render view template file // all page templates use "main.php" as alternative template file if( $page->template ) { $t = new TemplateFile($config->paths->templates . "view/{$page->template}.inc"); //$t->set("arr1", $somevar); echo $t->render(); } <?php /* * template views depending on template name * using regular php include */ if( $page->template ) { include($config->paths->templates . "view/{$page->template}.inc"); } I chosen this approach mainly because I hate splitting up the "main" template with head.inc and foot.inc etc. although I was also using this quite a lot, I like the delegate approach better. Having only one main.php which contains the complete html structure makes it easier for me to see/control whats going on. Hope this will be useful to someone. Cheers1 point
-
I like these two ideas Maybe I am under-thinking this but I but don't think these two ideas would be "very difficult" to implement? The main magic as I see it, happens in the default.php and topnav.inc (permissions check). See my proof of concept from a while back here..http://processwire.com/talk/topic/3754-proof-of-concept-processwire-admin-theme-switcher/ I would want the possibility to install multiple themes and choose which one to display. That's what I show in that post...If Admin themes were stored under "settings", changing themes would be a breeze.....Not sure how the upcoming theme switcher will look like though1 point
-
I would welcome the possibility of choosing a theme per role or user, like this we could build customized themes only for clients without worrying about a big part of the system (template editing, modules page, etc). From there, even deeper changes could be done.1 point
-
Interesting cross-platform solution, still in alpha http://www.lighttable.com/ (the project collectected $316,720 on a kickstarter campaign in 2012 http://www.kickstarter.com/projects/ibdknox/light-table) ------------ edit: I took some minutes to follow the getting started http://docs.lighttable.com/, and I must say I'm impressed (support for PHP is not great yet though)1 point
-
@Diogo, Maybe you'd like to clarify what you mean by "none of them worked well". I am not disputing your position, just pre-empting the inevitable question from others.."what did not work well?" {although Ryan maybe alluded to some of these above}. It will also keep this discussion going.1 point
-
Adrian, I went back to PMA as you advised and deleted all the tables of fieldtype Repeater -- and it solved the problem! Many, many thanks! Cliff1 point
-
1 point
-
<ryan> Make your version number 2 rather than 002. PHP might interpret that as Octal or something. </ryan> Very good tip drove me mad a while ago !1 point
-
Are you getting errors when trying to delete or add new repeater fields, or is just nothing happening? Sorry - you show the error in the subject I really haven't used repeater fields much at all, but if you are having problems deleting existing fields, you can do that through PMA as well. I wouldn't recommend deleting anything through PMA generally, but since you have already ventured in there and deleted all those pages, it sounds like that might have broken some things already anyway. Go into the "fields" table and delete the appropriate lines as well as deleting the "field_fieldname" tables. Or if you are cautious, wait for a more authoritative answer1 point
-
This is still not really finished. It definitely works and has been tested on a couple of different sites for several months now, but I think it still needs some refining before being ready for prime time. It is now on GitHub: https://github.com/adrianbj/ProcessPDFImageCreator Will wait for module directory submission until I get time to make some refinements though.1 point
-
Actually I think it is kind of a useful example that highlights what Martijn and I said above. ucwords won't work on capitalized strings, which is why that example of kongondo's doesn't show Meine Seite1 point
-
1 point
-
1 point
-
To problem 2. After testing we found that in where the language suddenly changes from "fr" to "default" is where we in API modify a user (not current) and save it. Afterwards the $user->language is set to "default" of the current user. THe culprit seems to be that after $page->save() there's a uncacheAll called which cleans out the $user->language set on runtime. We have now a workaround to save language before to a var, and give it back to the $user after the save. But it looks like when saving a user in front-end the $user->language set by the language system is reset.1 point
-
Thanks for testing Raymond. Just pushed a fix for this in the latest commit. Had to adjust the order that the operators were named in in the Javascript regex. You mentioned that your page field only holds a single page. As a result, the above can't work since it is asking for all of those IDs to match at the same time. Such a scenario would only be possible with a multi-page field. The OR syntax "|" in fields/values isn't yet supported for dependency selectors. I will be adding support for it, but not until everything else is considered stable with the dependencies. Basically, I'm trying to keep the number of variables at a minimum so that people can start using this stuff in a stable state sooner rather than later. You probably won't be able to do it exactly like that. But my plan is to let PW pre-process selectors to convert some things to page IDs before sending them to the Javascript side. For instance, you'll be able to do: d_product=/products/regioblad/ We might also be able to support: d_product.name=regioblad1 point
-
If that were to be a problem apeisa's redirect module http://modules.processwire.com/modules/process-redirects/ should help.1 point
-
Always visible page tree has it's merits. But I also find it little overwhelming. When I evaluated different CMS products few years back I did found Silverstripe interesting, but remember that "always visible pagetree" was little messy. PW way is much more "zen" This is how it looks now:1 point
-
Alessio, that's the intended behavior of filter. It changes your wireArray forever Use find() instead on your first foreach. $page->images->find("limit=4")1 point
-
Hi Mick, i have done the pop3 stuff of the module but I don't know how to do the whole story of your question. But maybe there is help with some kind of dirty hack: The sender is identified as $from and to get it out there and into a pw page you may set it into the $BodyText (like e.g. $BodyText = "<|$from|>\n"). This way you later can extract it from the page body once the page is created. Or you may look into the modules file if there is a way to hook into it somewhere before the page get created. btw: Do you know that there is also another module Process Email to Page. Maybe it supports what you need out of the box. (I don't know it, but there is a real chance it could be)1 point
-
Great work Philipp! I agree that the admin experience for non-tech or unexperienced users is really important for any CMS. I think that while ProcessWire has a nice admin it could really benefit with some of the ideas you're trying out. I had the same thought about what makes Wordpress so famous and user friendly and ultimately the design of the admin has played a big part in it. I want to stress out that I have nothing against the core admin ( ), but I think It could still be improved to achieve a more modern look (whatever that means) and be more user-friendly, which for me is the top concern towards using PW in commercial projects. I really like what some people have done with themes and such, but I still always use the default one. I would be awesome to have some special place in the forums to talk about design of the admin (that ships in core). Mostly to talk about the actual user experience and the user interface, and posting ideas (and iterating) with the core team. I am thinking that some of these ideas would eventually make it to core and I can see my clients (and people in general) benefiting a lot.1 point
-
I have just solved my own issue, but I want to document the solution in case other happy processwire users encounter the same problem. The solution is to simply rename the htaccess.txt file that was downloaded when processwire was installed to .htaccess and upload the renamed file. Apparently the renaming process occurs automagically upon installation so I was not aware that I was overwriting a critical file. BIll1 point
-
They work in 2.3.0 too, it's just that they are a whole lot farther along in 2.3.4 than in 2.3.0 (and more stable too). So if you are building a site around multi-language URLs, it's worth the risk of using a dev branch (IMO) relative to the benefits you get in this aspect.1 point
-
You might try adding this to the end of your /site/config.php: $config->sessionName = "sevarf2"; session_name($config->sessionName); session_set_cookie_params(0, '/', '.mydomain.com');1 point
-
I've gone ahead and committed the Inputfield dependencies to the dev branch, for anyone that would like to help test. I've also posted a documentation page that explains how and where to use them, current limitations and examples. There are a near infinite number of potential scenarios on how these things could be used, so it's not possible for me to test everything locally. As a result, expect bugs and please report them when you find them. Thanks in advance for your help in testing. For non-default admin themes, some updates have to be made in order to support field dependencies. As a result, unless you are an admin theme developer, it's best to stick to the default admin theme when using field dependencies, temporarily. Field dependencies can also be used in FormBuilder. Though I've not done a lot of testing in FormBuilder yet, so don't recommend using field dependencies in front-end production forms just yet. Though in my initial testing, they seem to work just fine. Thanks again to Antti/Avoine for sponsoring field dependencies!1 point
-
Thanks guys, glad that you like how this is looking. Though you are giving me more credit here than I deserve. I didn't realize there would be so much interest in it, otherwise I'd have worked on it sooner! It's been on the to-do list for awhile (with a million other things), but didn't become urgent till I remembered/found out it was needed by the end of August. So figured I better get busy! I like the way they define them there too. Longer term, I'd like to make a new Selectors inputfield that lets you build selectors this way, because it's a little more friendly in some ways, even if less flexible in others. But it's a good option to provide in addition to text input of selectors. However, I'll build that Inputfield later as something separate from field dependencies, so that it can be used elsewhere and by other modules, etc. I agree, especially in the context of the video. Though I also think subtlety is important so that required labels don't become a distraction (especially for common required fields like 'title'). If a field is required, and the user missed the visual que, they will still find out about it when they save. The field dependencies just add (or remove) the "required" class to the .Inputfield container, so the actual look of required fields is dependent upon the admin theme. But I think the field dependencies could do a quick fade-out/fade-in to indicate that something has changed about the field's state. I appreciate the compliment. But this is just not true. There are always bugs to fix, and I'm sure there will be several to find and fix with field dependencies, just like anything else (perhaps more so, given some of the complexity in it). So when those of you on the dev branch start using this, don't expect everything to work perfectly. Instead, experiment, test and tell me when you find something that doesn't work quite right. There are so many scenarios that could happen with field dependencies that it may take a few iterations till we've covered them all. There are also some fieldtypes that may not be compatible with field dependencies. For instance, we don't currently have a way of polling the value from the rich text editors, since they don't update the related <textarea> elements on the fly. We could do it by accessing the TinyMCE and/or CKEditor API functions, but I'm not sure that I want to bundle TinyMCE or CKEditor-specific code into the field dependencies–that's the type of dependency you usually want to avoid in code. So you'll be able to show/hide rich text fields based on the values from other fields, but not based on the values in a rich text field. To be honest, I'm not sure that's a problem though, as I don't see rich text fields as being likely sources of dependencies anyway. Those 3 fields are configured in the template for 33%, 34%, 33% width. Without field dependencies they would all fit on one row. When a field is removed from the mix as a result of a dependency, it simply expands the width of the last remaining field to fill out the row. The concept is really simple. It came about because I didn't like the look of the uneven rows when I started dynamically removing fields as a result of dependencies. While the concept is simple, the implementation proved to be a challenge... it's one of those things I thought would take 30 mins, and it ended taking much longer. Though a good part of that is just that I don't use Javascript every day (I'm definitely not an expert at it), so it can take me awhile to get things right.1 point
-
I asked the same question from Ryan. It is pretty clever stuff actually: There is also a hint why Ryan deliveres rock solid from the beginning1 point
-
This hasn't been asked, but wanted to cover how the permissions and publish workflow work on the site. It has a very simple, though nice setup, where authors can submit new posts but can't edit already published posts, nor can they edit unpublished posts by other authors. It enables Mike to have full control over any content that gets published on the site, while still allowing easy submission and edits for the authors. Post workflow All of the authors have a role called "author" with page-edit permission. On the "post" template, the boxes for "edit" and "create" are checked for this "author" role. This site also makes use of the page-publish permission, which is an optional one in ProcessWire that you can add just by creating a new permission and naming it "page-publish". Once present, it modifies the behavior of the usual page-edit permission, so that one must also have page-publish in order to publish pages or edit already published pages. The "author" role does not have page-publish permission. As a result, authors on the site can submit posts but can't publish them. Nor can they edit already published posts. In this manner, Mike has final say on anything that gets posted to the site. Post ownership The default behavior in ProcessWire is that the Role settings control all access... meaning all users with role "author" would be able to do the same things, on the same pages. In this case, we don't want one author to be able to edit an unpublished/pending post created by another author. This was easily accomplished by adding a hook to /site/templates/admin.php: /** * Prevent users from being able to edit pages created by other users of the same role * * This basically enforces an 'owner' for pages * */ wire()->addHookAfter('Page::editable', function($event) { if(!$event->return) return; // already determined user has no access if(wire('user')->isSuperuser()) return; // superuser always allowed $page = $event->object; // if user that created the page is not the current user, don't give them access if($page->createdUser->id != wire('user')->id) $event->return = false; }); Planned workflow improvements Currently an author has to let Mike know "hey my article is ready to be published, can you take a look?". This is done by email, I'm assuming. An addition I'd like to make is to add a Page reference field called "publish_status" where the author can select from: DRAFT: This is a work in progress (default) PUBLISH: Ready for review and publishing CHANGE: Changes requested - see editor notes DELETE: Request deletion Beyond that, there is also an "editor_notes" text field that only appears in the admin. It's a place where Mike and the author can communicate, if necessary, about the publish status. This editor_notes field doesn't appear on the front-end of the site. All this can be done in ProcessWire just by creating a new field and adding these as selectable page references. That's easy enough, but I want to make it so that it notifies both Mike (the reviewer) and the author by email, every time there is a change in publish status or to the editor_notes. This will be done via another hook in the /site/templates/admin.php: wire()->addHookAfter('Page::saveReady', function($event) { // get the page about to be saved $page = $event->arguments(0); // if this isn't a post, don't continue if($page->template != 'post' || !$page->id) return; // if this post wasn't made by an "author" don't continue if(!$page->createdUser->hasRole('author')) return; $subject = ''; $message = ''; if($page->isChanged('publish_status') || $page->isChanged('editor_notes')) { // the publish status or editor notes have changed $subject = "CMSCritic post publish status"; $notes = $page->isChanged('editor_notes') ? "Notes: $page->editor_notes" : ""; $message = " Title: $page->title\n URL: $page->httpUrl\n Status: {$page->publish_status->title}\n $notes "; } else if($page->isChanged('status') && !$page->is(Page::statusUnpublished)) { // page was just published $subject = "CMSCritic post published"; $message = "The post $page->httpUrl has been published!"; } if($message) { $reviewer = wire('users')->get('mike'); $author = $page->createdUser; mail("$reviewer->email, $author->email", $subject, $message); $this->message("Email sent: $subject"); } }); Mike, if you are reading this, does this sound useful to you?1 point
-
For authors, there were only about 6 of them at import time, so I created the authors as users in PW manually. I also added the "wpid" field to the "user" template, and populated the value of that manually. That was easy to find in WordPress just by editing the author and noting the ID in the URL. The WordPress wp_posts table has a field in it called post_author, which is the ID of the author. So assuming we've got a user in ProcessWire with a "wpid" that matches up to that, it's easy for us to assign the right PW user to each post. You'll see how this takes place in the code below. Wrapping it up Here is the same "import" code as in the first post, but I added all the code accounting for authors, topics, tags, and images back into it. This all just goes in a ProcessWire template file, and viewing the page triggers the import. Because it's aware of stuff that is already imported, it can be run multiple times without causing duplication. <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Import Posts</title> </head> <body> <table border='1' width='100%'> <thead> <tr> <th>New?</th> <th>ID</th> <th>Author</th> <th>Date</th> <th>Name</th> <th>Title</th> <th>Images</th> <th>Topics</th> <th>Changes</th> </tr> </thead> <tbody> <?php // get access to WordPress wpautop() function include("/path/to/wordpress/wp-includes/formatting.php"); $wpdb = new PDO("mysql:dbname=wp_cmscritic;host=localhost", "user", "pass", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'")); $posts = wire('pages')->get('/posts/'); $sql = " SELECT * FROM wp_posts WHERE post_type='post' AND post_status='publish' ORDER BY post_date "; $query = $wpdb->prepare($sql); $query->execute(); while($row = $query->fetch(PDO::FETCH_ASSOC)) { $post = $posts->child("wpid=$row[ID]"); // do we already have this post? if(!$post->id) { // create a new post $post = new Page(); $post->template = 'post'; $post->parent = $posts; echo "Creating new post...\n"; } $post->of(false); $post->name = wire('sanitizer')->pageName($row['post_name']); $post->title = $row['post_title']; $post->date = $row['post_date']; $post->summary = $row['post_excerpt']; $post->wpid = $row['ID']; // find the post author $author = wire('users')->get("wpid=$row[post_author]"); // if we don't have this post author, assign one (Mike) if(!$author->id) $author = wire('users')->get("mike"); // set the post author back to the page $post->createdUser = $author; // assign the bodycopy after adding <p> tags // the wpautop() function is from WordPress /wp-includes/wp-formatting.php $post->body = wpautop($row['post_content']); // give detailed report about this post echo "<tr>" . "<td>" . ($post->id ? "No" : "Yes") . "</td>" . "<td>$row[ID]</td>" . "<td>$row[post_author]</td>" . "<td>$row[post_date]</td>" . "<td>$row[post_name]</td>" . "<td>$row[post_title]</td>" . "<td>" . importImages($post) . "</td>" . "<td>" . importTopicsAndTags($wpdb, $post) . "</td>" . "<td>" . implode('<br>', $post->getChanges()) . "</td>" . "</tr>"; $post->save(); } function importTopicsAndTags(PDO $wpdb, Page $page) { // see implementation in previous post } function importImages(Page $page) { // see implementation in previous post } ?> </tbody> </table> </body> </html>1 point
-
Topics and tags: The first step was to create the parent pages and templates for these. For topics, there were only a few of them, so I created all the category pages ahead of time. On the other hand, with tags, there are 2000+ of those, so those are imported separately. Here are the manual steps that I performed in the PW admin before importing topics and tags: Created template "topics" and page /topics/ that uses this template. Created template "topic" and 6 topic pages that use it, like /topics/cms-reviews/ for example. Created Page reference field "topics" with asmSelect input, set to use parent /topics/ and template "topic". Created template "tags" and page /tag/ that uses this template. Note that I used /tag/ as the URL rather than /tags/ for consistency with the old WordPress URLs. Otherwise I would prefer /tags/ as the URL for consistency with the template name. Created template "tag". Created Page reference field "tags" with PageAutocomplete input, set to use parent /tag/ and template "tag". I also set this one to allow creating of new pages from the field, so the admin can add new tags on the fly. Added the new "topics" and "tags" fields to the "post" template. With all the right templates, fields and pages setup, we're ready to import. WordPress stores the topics, tags and the relationships of them to posts in various tables, which you'll see referenced in the SQL query below. It took some experimenting with queries in PhpMyAdmin before I figured it out. But once I got the query down, I put it in a function called importTopicsAndTags(). This function needs a connection to the WordPress database, which is passed into the function as $wpdb. For more details on $wpdb, see the first post in this thread. /** * Import WordPress topics and tags to ProcessWire * * This function assumes you will do your own $page->save(); later. * * @param PDO $wpdb Connection to WordPress database * @param Page $page The ProcessWire "post" page you want to add topics and tags to. * This page must have a populated "wpid" field. * @return string Report of what was done. * */ function importTopicsAndTags(PDO $wpdb, Page $page) { $out = ''; $sql = <<< _SQL SELECT wp_term_relationships.term_taxonomy_id, wp_term_taxonomy.taxonomy, wp_term_taxonomy.description, wp_terms.name, wp_terms.slug FROM wp_term_relationships LEFT JOIN wp_term_taxonomy ON wp_term_taxonomy.term_taxonomy_id=wp_term_relationships.term_taxonomy_id LEFT JOIN wp_terms ON wp_terms.term_id=wp_term_taxonomy.term_id WHERE wp_term_relationships.object_id=$page->wpid ORDER BY wp_term_relationships.term_order _SQL; $query = $wpdb->prepare($sql); $query->execute(); while($row = $query->fetch(PDO::FETCH_ASSOC)) { if($row['taxonomy'] == 'category') { // this is a topic: find the existing topic in PW $topic = wire('pages')->get("/topics/$row[slug]/"); if($topic->id) { // if $page doesn't already have this topic, add it if(!$page->topics->has($topic)) $page->topics->add($topic); // report what we did $out .= "<div>Topic: $topic->title</div>"; } } else if($row['taxonomy'] == 'post_tag') { // this is a tag: see if we already have it in PW $tag = wire('pages')->get("/tag/$row[slug]/"); if(!$tag->id) { // we don't already have this tag, so create it $tag = new Page(); $tag->template = 'tag'; $tag->parent = '/tag/'; $tag->name = $row['slug']; $tag->title = $row['name']; $tag->save(); } // if $page doesn't already have this tag, add it if(!$page->tags->has($tag)) { $page->tags->add($tag); $out .= "<div>Tag: $tag->title</div>"; } } } return $out; }1 point
-
Type in your home template or else. $u = $users->get('admin'); $u->of(false); $u->pass = 'superSecretPassword'; $u->save(); Then go to a page with that template. Then go to /processwire/ & login. --- I almost forgot: Welcome Bosse1981 !1 point
-
If you are using the latest versions of jQuery close-link is not working. The solution: Replace the file AjaxSearch.js line # 95 From: .live('click',function(){ On: .on('click',function(){ Excuse me for my English, I use Google Translate1 point
-
Nothing will be as fast as going straight to a dedicated targeted SQL query like that. But if you wanted to use PW selectors, this is still quite fast: for($n = ord('A'); $n <= ord('Z'); $n++) { $letter = chr($n); $cnt = $pages->count("surname^=$letter"); echo "<li>$letter - $cnt people</li>"; }1 point
-
WireArray::getRandom() can be "too" random for my taste - I wanted some Page items to rotate randomly on a daily basis, rather than every page load, so I came up with this: /** * Select random pages from a PageArray * * If no $seed is provided, today's date is used to seed the random number * generator, so you can use this function to rotate items on a daily basis. * * @param PageArray $pages the list of Page object to select from * @param int $amount the amount of items to extract from the given list * @param int|null $seed a number used to see the random number generator */ public function randomPages(PageArray $pages, $amount=1, $seed=null) { if ($seed === null) { $seed = crc32(date('Ymd')); } srand($seed); $keys = $pages->getKeys(); $selected = new PageArray(); while (count($keys) > 0 && count($selected) < $amount) { $index = rand(0, count($keys)-1); $key = $keys[$index]; $selected->add($pages[$key]); array_splice($keys, $index, 1); } return $selected; } I thought I would post it here for others to use. I wonder if this is useful enough that it (or something similar) should be part of the core? I personally find that "totally random" is rarely useful or desirable in real life - for one, pages that change on every request may harm your search-engine ranking. For another, users may find it confusing that your site changes all the time - "hey, what was that thing I just saw" doesn't work for the person who goes back to the front-page to see "that other thing" he just saw, when you constantly swap things out between every page view... Just my opinion, for what it's worth1 point
-
Perhaps even better: /** * Select random pages from a PageArray * * If no $seed is provided, today's date is used to seed the random number * generator, so you can use this function to rotate items on a daily basis. * * @param PageArray $pages the list of Page object to select from * @param int $amount the amount of items to extract from the given list * @param int|string $seed a number used to see the random number generator; or a string compatible with date() */ public function randomPages(PageArray $pages, $amount=1, $seed='Ymd') { if (is_string($seed)) { $seed = crc32(date($seed)); } srand($seed); $keys = $pages->getKeys(); $selected = new PageArray(); while (count($keys) > 0 && count($selected) < $amount) { $index = rand(0, count($keys)-1); $key = $keys[$index]; $selected->add($pages[$key]); array_splice($keys, $index, 1); } return $selected; } Now you can seed with a date()-compatible string, so you can rotate weekly (for example) using "YW", or monthly using "Ym", etc.1 point