Leaderboard
Popular Content
Showing content with the highest reputation on 11/20/2013 in all areas
-
I spent a couple of hours hacking/tweaking Ryan's module today as well, did some searching and found this thread. The access control model isn't working so well for my needs. I also need to grant certain users view/edit permissions from a branch down. How come access control is tied to Templates? I mean, it makes sense in some instances - and it's easy to extend the security model and build custom authorization rules on the front-end, but on the back-end it's not as easy as I had hoped for. I think part of the issue is that RBAC frameworks normally have two access control components - rights and permissions. Rights are the binary grants you give to users or groups - meaning you either have a given right or you don't. Rights don't traditionally have any parameters - therefore rights usually are more granular in their descriptions, e.g. "can edit all posts" and "can edit posts created by me" are two distinct rights. The rights are independent from permissions, which are defined in code - permissions are checks you can actually perform, and they usually have access to a "context" which might consist of current user, current page, current template, today's date, and of course the current user's rights - anything you might want to use for security checks. An example of a permission would be "can edit post", which might check for several rights, e.g. "can edit all posts", and "can edit posts created by me" which it would check by getting the current Page object from the "context". I get why it's implemented the way it is - for one, you want to be able to filter pages based on rights, at query-time. With a traditional RBAC model, that is not possible. But so many other things aren't possible with a fixed security model - it grows increasingly complex with increasing requirements, and it gets more rigid the more you extend it. Traditional RBAC can be extended indefinitely and never really increases in complexity because all of it's part function independently. I think a more traditional RBAC model could be really flexible and incredibly scalable if implemented using hooks in ProcessWire - modules could easily add new permission methods and new security context properties with hooks. I could see this making ProcessWire much more attractive as a platform for multi-tenant applications, where free-form access control is really crucial.4 points
-
New site launched today: http://www.katonahartcenter.com/ Thanks to everyone in the forum who answered my posts over the last 8 weeks of developing this site, including adrian, teppo & ryan. modules so far that were essential: After Save Actions Color Picker Admin Custom Pages DataTable Redirects Template Decorator Form Save Reminder Hanna Code Hanna Code Helper Twitter Feed Version Control for Text Fields Form Builder ProCache Forum Threads that helped: http://processwire.com/talk/topic/4849-search-rar-and-tar-result-in-404/ http://processwire.com/talk/topic/4866-time-field/ http://processwire.com/talk/topic/3745-hanna-code/ http://processwire.com/talk/topic/4816-set-field-value-globally-if-null/ http://processwire.com/talk/topic/4602-flexible-downloads-using-pages/ http://processwire.com/talk/topic/1648-ok-to-change-page-name-path-after-save/ http://processwire.com/talk/topic/3987-cmscritic-development-case-study/?p=36867 http://processwire.com/talk/topic/3812-htaccess/?p=37295 using custom admin pages:3 points
-
First of all, my examples were not right - not at all, sorry. Now they're fixed. The problem is that you're limiting pages under each "subchild" separately, not all grandchildren at once. Here's one way to get there: $limit = 4; $cats = $pages->get("/mypage/")->children; foreach ($cats as $cat) { $menu .= "<div>"; $menu .= "<h2 class='titlebg'>$cat->title</h2>"; $grandchildren = $pages->find("parent={$cat->children}, limit=$limit, sort=-date, sort=title"); if($grandchildren) { // if they have GRANDchildren $menu .= "<ul>"; foreach($grandchildren as $child) { $menu .= "<li><a href='{$child->url}'>$child->title</a></li>"; } $menu .= "</ul>"; if($grandchildren->getTotal() > $limit) $menu .= "<span><a href='{$cat->url}'>See More</a></span>"; } $menu .= "</div>"; } This would give (with the example structure again): cat1 cat2 child2.1.1 child2.1.2 child2.1.3 child2.2.1 See More cat3 child3.1.1 This trick to get grandchildren ("parent={$cat->children}") would not be the way to go if there were a lot of "subchild" pages under any "cat" page. This is because the selector expands to something like "parent=1234|1235|1236|1237|...|1507|1508" giving a too long selector string at one point. But assuming there aren't more than a couple of dozen of them, this would work just fine. I also added a little condition to show "See more" only if there are more grandchildren to see - just as an example.3 points
-
Almost If there is a page found, a Page object is returned, which always has an id > 0. If there is no page found, a NullPage object is returned, which always has the id = 0. the id is either equal to zero or greater, but never empty.2 points
-
When I ran Google Developers PageSpeed Insights to check out my developed website for performance and improvement I found that my images (thumbnails, backgrounds, etc...) can be compress more than what I have so I look for Image Compression Tools and this what I found http://www.creativebloq.com/design/image-compression-tools-1132865 I hope this helps other too.2 points
-
I have used a lot of time with this issue. The bigger and more complex sites we build, the more "ad hoc" UA is needed. Defining access on "who can access/edit news" is not relevant when your site has 20 news archives for different groups. Or when you want to create new "workgroup" and choose who can access that. Of course all these can be build custom, but it is lots of work and PW doesn't provide anything as a base for that. I have module baking that solves this very issue. It has basic functionality already made and it for most parts bypass the template based UA totally. This is by intention very simple at this first stage: just view and edit rights and user that belong to groups (one user can belong to many groups). Not sure about the licensing yet, I might release this as a commercial module, but also happy to transform it to a open source project for community (if you guys feel this is promising). Ryan has seen the code and we did hit one core problem: circular reference. My module requires page field that many times references itself. This creates problems in certain situations: actually only when page is saved but no changes is made. It is not ready yet, but the basic functionality should be there. I have build this few times already and always from different angle. I believe this is the most simple one (see the find hook that has been the problem in those previous modules). Anyways, I know at least Teppo and Nik have been interested in this, so here we go: https://github.com/apeisa/UserGroups/2 points
-
This module allows you to automatically rename file (including image) uploads according to a configurable format This module lets you define as many rules as you need to determine how uploaded files will be named and you can have different rules for different pages, templates, fields, and file extensions, or one rule for all uploads. Renaming works for files uploaded via the admin interface and also via the API, including images added from remote URLs. Github: https://github.com/adrianbj/CustomUploadNames Modules Directory: http://modules.processwire.com/modules/process-custom-upload-names/ Renaming Rules The module config allows you to set an unlimited number of Rename Rules. You can define rules to specific fields, templates, pages, and file extensions. If a rule option is left blank, the rule with be applied to all fields/templates/pages/extensions. Leave Filename Format blank to prevent renaming for a specific field/template/page combo, overriding a more general rule. Rules are processed in order, so put more specific rules before more general ones. You can drag to change the order of rules as needed. The following variables can be used in the filename format: $page, $template, $field, and $file. For some of these (eg. $field->description), if they haven't been filled out and saved prior to uploading the image, renaming won't occur on upload, but will happen on page save (could be an issue if image has already been inserted into RTE/HTML field before page save). Some examples: $page->title mysite-{$template->name}-images $field->label $file->description {$page->name}-{$file->filesize}-kb prefix-[Y-m-d_H-i-s]-suffix (anything inside square brackets is is considered to be a PHP date format for the current date/time) randstring[n] (where n is the number of characters you want in the string) ### (custom number mask, eg. 001 if more than one image with same name on a page. This is an enhanced version of the automatic addition of numbers if required) If 'Rename on Save' is checked files will be renamed again each time a page is saved (admin or front-end via API). WARNING: this setting will break any direct links to the old filename, which is particularly relevant for images inserted into RTE/HTML fields. The Filename Format can be defined using plain text and PW $page variable, for example: mysite-{$page->path} You can preserve the uploaded filename for certain rules. This will allow you to set a general renaming rule for your entire site, but then add a rule for a specific page/template/field that does not rename the uploaded file. Just simply build the rule, but leave the Filename Format field empty. You can specify an optional character limit (to nearest whole word) for the length of the filename - useful if you are using $page->path, $path->name etc and have very long page names - eg. news articles, publication titles etc. NOTE - if you are using ProcessWire's webp features, be sure to use the useSrcExt because if you have jpg and png files on the same page and your rename rules result in the same name, you need to maintain the src extension so they are kept as separate files. $config->webpOptions = array( 'useSrcExt' => false, // Use source file extension in webp filename? (file.jpg.webp rather than file.webp) ); Acknowledgments The module config settings make use of code from Pete's EmailToPage module and the renaming function is based on this code from Ryan: http://processwire.com/talk/topic/3299-ability-to-define-convention-for-image-and-file-upload-names/?p=32623 (also see this post for his thoughts on file renaming and why it is the lazy way out - worth a read before deciding to use this module). NOTE: This should not be needed on most sites, but I work with lots of sites that host PDFs and photos/vectors that are available for download and I have always renamed the files on upload because clients will often upload files with horrible meaningless filenames like: Final ReportV6 web version for John Feb 23.PDF1 point
-
Since you guys asked for it, I'll take a stab at a case study on the development process. Most of the development was done in about a week and a half. I started with the basic profile, but it ended up being something somewhat similar to the Blog profile in terms of how it's structured. Below I'll cover some details on the biggest parts of the project, which included data conversion, the template structure, the front-end development and anything else I can think of. Data Conversion from WordPress to ProcessWire One of the larger parts of the project was converting all of the data over from WordPress to ProcessWire. I wrote a conversion script so that we could re-import as many times as needed since new stories get added to cmscritic.com almost daily. In order to get the data out of WordPress, I queried the WordPress database directly (my local copy of it anyway) to extract what we needed from the tables wp_posts for the blog posts and pages, and then wp_terms, wp_term_relationships, and wp_term_taxonomy for the topics and tags. WordPress stores its TinyMCE text in a state that is something in between text and HTML, with the most obvious thing being that there are no <p> tags present in the wp_posts database. Rather than trying to figure out the full methodology behind that, I just included WP's wp-formatting.php file and ran the wpautop() function on the body text before inserting into ProcessWire. I know a lot of people have bad things to say about WordPress's architecture, but I must admit that the fact that I can just include a single file from WordPress's core without worrying about any other dependencies was a nice situation, at least in this case. In order to keep track of the WordPress pages imported into ProcessWire through repeat imports, I kept a "wpid" field in ProcessWire. That just held the WordPress post ID from the wp_posts table. That way, when importing, I could very easily tell if we needed to create a new page or modify an existing one. Another factor that had to be considered during import was that the site used a lot of "Hana code", which looked like [hana-code-insert name="something" /]. I solved this by making our own version of the Hanna code module, which was posted earlier this week. Here's an abbreviated look at how to import posts from WordPress to ProcessWire: $wpdb = new PDO("mysql:dbname=wp_cmscritic;host=localhost", "root", "root", 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']; // assign the bodycopy after adding <p> tags // the wpautop() function is from WordPress /wp-includes/wp-formatting.php $post->body = wpautop($row['post_content']); $post->save(); echo "Saved post: $post->path\n"; } What I've left out here is the importing of images, topics, tags, and setting the correct authors for each post. If anyone is interested, I'll be happy to go more in depth on that, but didn't want to overwhelm this message with code. Template File Structure This site makes use of the $config->prependTemplateFile to automatically include the file _init.php before rendering a template file, and $config->appendTemplateFile to automatically include the file _main.php after. So the /site/config.php has this: $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; You may recognize this as being the same setup from the Skyscrapers profile. The _init.php includes files containing functions we want to be available to all of our templates, and set default values for the regions we populate: /site/templates/_init.php /** * Include function and hook definition files * */ require_once("./includes/render.php"); require_once("./includes/hooks.php"); /** * Initialize variables populated by templates that get output in _main.php * */ $browserTitle = $page->get('browser_title|title'); $body = "<h1>" . $page->get('headline|title') . "</h1>" . $page->body; $side = ''; $renderMain = true; // whether to include the _main.php file The includes/render.php file that is included above includes several functions for generating markup of navigation and post summaries, or any other shared markup generation functions. Examples are renderPost(), renderNav(), renderTags(). This is similar to the blog.inc file from the Blog profile except that I'm letting these functions generate and return their own markup rather than splitting them into separate view files. I personally find this easier to maintain even if it's not as MVC. The includes/hooks.php sets up any hooks I want to be present for all of my templates. I could have also done this with an autoload module, but found this to just be a little simpler since my hooks were only needed on the front-end. The main hook of interest is one that makes all posts look like they live off the root "/" level rather than "/posts/" (where they actually live). This was in order to keep consistency with the URLs as they were in WordPress, so that the new site would have all the same URL as the old site, without the need for 301 redirects. /site/templates/includes/hooks.php /** * This hook modifies the default behavior of the Page::path function (and thereby Page::url) * * The primary purpose is to redefine blog posts to be accessed at a URL off the root level * rather than under /posts/ (where they actually live). * */ wire()->addHookBefore('Page::path', function($event) { $page = $event->object; if($page->template == 'post') { // ensure that pages with template 'post' live off the root rather than '/posts/' $event->replace = true; $event->return = "/$page->name/"; } }); Our /site/templates/_main.php contains the entire markup for the overall template used site wide, from <html> to </html>. It outputs those variables we defined in _init.php in the right places. For example, $body gets output in the <div id='bodycopy'>, $side gets output in the right <aside>, and $browserTitle gets output in the <title> tag. /site/templates/_main.php <?php if($renderMain): ?> <html> <head> <title><?=$browserTitle?></title> </head> <body> <div id='masthead'> // ... </div> <div id='content'> <div id='bodycopy'><?=$body?></div> <aside id='sidebar'><?=$side?></aside> </div> <footer> // ... </footer> </body> </html> <?php endif; ?> We use the rest of the site's template files to simply populate those $body, $side and $browserTitle variables with the contents of the page. As an example, this is an abbreviated version of the /site/templates/post.php template: /site/templates/post.php // functions from /site/templates/includes/render.php $meta = renderMeta($page); $tags = renderTags($page); $authorBox = renderAuthor($page->createdUser); $comments = renderComments($page); $body = " <article class='post post-full'> <header> <h1>$page->title</h1> $meta </header> $page->body $tags $authorBox $comments </article> "; if(count($page->related)) { $side = "<h4>Related Stories</h4>" . renderNav($page->related); } What might also be of interest is the homepage template, as it handles the other part of routing of post URLs since they are living off the root rather than in /posts/. That means the homepage is what is triggering the render of each post: /site/templates/home.php if(strlen($input->urlSegment2)) { // we only accept 1 URL segment here, so 404 if there are any more throw new Wire404Exception(); } else if(strlen($input->urlSegment1)) { // render the blog post named in urlSegment1 $name = $sanitizer->pageName($input->urlSegment1); $post = $pages->get("/posts/")->child("name=$name"); if($post->id) echo $post->render(); else throw new Wire404Exception(); // tell _main.php not to include itself after this $renderMain = false; } else { // regular homepage output $limit = 7; // number of posts to render per page $posts = $pages->find("parent=/posts/, limit=$limit, sort=-date"); $body = renderPosts($posts); } The rest of the site's template files were handled in the same way. Though most were a little simpler than this. Several were simply blank, since the default values populated in _init.php were all that some needed. Front-end development using Foundation 4 The front-end was developed with the Foundation 4 CSS framework. I started with the Foundation blog template and then tweaked the markup and css till I had something that I thought was workable. Then Mike and I sent the _main.php template file back and forth a few times, tweaking and changing it further. There was no formal design process here. It was kind of a photoshop tennis (but in markup and CSS) where we collaborated on it equally, but all under Mike's direction. After a day or two of collaboration, I think we both felt like we had something that was very good for the reader, even if it didn't originate from a design in Photoshop or some other tool like that. I think it helps a lot that Foundation provides a great starting point and lends itself well to fine tuning it the way you want it. I also felt that the mobile-first methodology worked particularly well here. Comments System using Disqus We converted the comments system over to Disqus while the site was still running WordPress. This was done for a few reasons: Disqus comments provide one of the best experiences for the user, in my opinion. They also are platform agnostic, in that we could convert the whole site from WP to PW and not have to change a thing about the comments… no data conversion or importing necessary. Lastly, ProcessWire's built-in comments system is not quite as powerful as WordPress's yet, so I wanted cmscritic.com to get an upgrade in that area rather than anything else, and Disqus is definitely an upgrade from WP's comments. In order to ensure that Disqus could recognize the relations of comment threads to posts, we again made use of that $page->wpid variable that keeps the original WordPress ID, and also relates to the ID used by the Disqus comments. This is only for posts that originated in WordPress, as new posts use a ProcessWire-specific ID.1 point
-
Hey guys, I'm new here, and I'm loving ProcessWire and the community spirit so far. We're just about to start using ProcessWire for our new clients requiring PHP solutions. Moving in a Rails direction, structure in our projects is becoming more and more of a necessity. As such, I've tried to employ some MVCish techniques in creating a boilerplate for ProcessWire for getting projects going quickly. One of the primary goals of this structure is to make it easier to separate logic from markup, and to prevent tags from being split over templates. Keeping `body`, `html`, and structural markup open and close tags in the same file greatly reduces cognitive overhead, and reduces opportunities for mismatching tags to exist. This approach also reduces duplication, and is great for keeping files small, focused, and organised. The main structure of the boilerplate is well defined, and ready to use in production. The repo is available here: https://github.com/fixate/pw-mvc-boilerplate (link updated 2014/01/17) Structure Although not completely MVC (using classes for controllers feels redundant, there are no models, and a full MVC approach will require a fair amount of customisation), it is heavily MVC inspired. Additionally, the structure is an extension of Soma's delegate approach. File structure: ├── site ├── assets ├── modules . . . ├── templates // boilerplate contents here ├── assets // css, js, fonts, images, etc. ├── controllers // variables and functions specific to templates ├── errors ├── partials // markup not specific to any particular template ├── views // layouts specific to a template ├── _init.php // used to load global and template-specific controllers ├── main.php // the 'alternate template' for all templates . . . **NB: This structure has largely been updated and improved - see the UPDATE - 2014/01/17 at the bottom of this post! Controllers Controllers hold template specific variables and functions. There is also a global controller responsible for making global fields, such as SEO fields, available everywhere, as well as being responsible for the actual delegation. Template logic should be handled as much as possible from within controllers. Views Views are responsible for handling markup and output. Views have available to them both the global controller, and their own controller. Logic should be, as much as makes sense, handled in a controller, with the view pulling the results in for display. Partials Partials hold markup not specific to any particular template on its own, such as the `<head>`, header, navigation, scripts, or footer. As with views, it is best to keep these as logicless as possible. _init.php _init.php is responsible for making controllers available to views. Controllers are only included if they exist - sometimes a template-specific controller may not be necessary, in which case you won't need to create one. main.php main.php is the default layout (equivalent to layout/application.html.erb in Rails) into which everything is rendered. This file has been kept small deliberately to let partials and views manage more fine grained markup structures, while this file serves the main site structure. A call to render_view(), defined in global-controller.php, is responsible for delegating rendering to the view of the current template. Additionally, there is a constant defined in globals-controller.php useful for serving different assets depending on if you are working in a local environment, or if your site is live. This is useful for preventing Google Analytics from running in a dev environment, or for using unminified scripts for debugging. This boilerplate eliminates the need to do much configuration when beginning a project, apart from having to change each template's alternate template in the admin. I hope this will assist in quickly organising and developing new projects! ------------------------------ UPDATE - 2014/01/17: ------------------------------ All files for rendering are postfixed with .html.php in good ol' Rails fashion. main.php has been removed in favour of mvc.php. mvc.php requires config/boot.php which then handles which controllers, views, etc. are used the main layout is now found in views/layouts/application.html.php - like Rails again. partials are now kept inside views/ each page template can have its own optional controller, or simply inherit functionality only from ApplicationController ├── site ├── assets ├── modules . . . ├── templates // boilerplate contents here ├── assets // css, js, fonts, images, etc. ├── controllers // variables and functions specific to templates ├── core // core mvc files - base controllers etc. (project specific stuff does not go here) ├── errors ├── views // folder for template files, layout files, and partials ├── layouts // application layout ├── partials // markup not specific to any particular template ├── mvc.php // the 'alternate template' for all templates . . .1 point
-
Hi all, I'm having an issue with getting fields to display on page creation. I've set a template to allow for only a single specific template to be used for immediate child pages. When a user creates a new child page, only the title and name fields are appearing for entry, even though it has recognised that the page has to be created with a specific template. Is there any way to get all fields associated with the new pages template to show, so that the user doesn't have to click the save button before filling in the rest of the form? Seeing as the system knows what template is, I don't see why it can't just display all the fields on creating a new page. Thanks!1 point
-
Change your if to: if ($fwd->id) { //... } Because if there's no page found, Pw returns a NullPage object (with id=0). Your current if is always true, because $fwd is an object. Edit: nik 1, wanze 01 point
-
Hi Alejandro! That else-block is never executed, that's why the page does not get created and rendered. This is because $pages->get() "Returns a Page, or a NullPage if not found.". So $fwd is always an object (either a Page or a NullPage) and "if($fwd)" is always true. Test for the page id to see if you got a real page, like this: if($fwd->id) { ... } else { ... } (And remember to sanitize $transaction_id if it's part of user input.)1 point
-
Hi Rjay- here is my example, this one uses dates in certain conditions and also page ids... https://gist.github.com/outflux3/7568222 this module works on the current dev, not sure if it works on the stable though should also mention that this is entirely based on the initial buildUrl module that pete posted on the link a few posts up1 point
-
I'm sure there's a better way - if only I knew what you're trying to achieve exactly . Here's an example of a page structure to demonstrate what's happening: With "limit=2" your code prints out: cat1 cat2 child2.1.1 child2.1.2 child2.2.1 child2.2.2 cat3 And with "limit=3": cat1 cat2 child2.1.1 child2.1.2 child2.1.3 child2.2.1 child2.2.2 cat3 Reading the code, it's pretty much expected output to me, but obviously not the one you're after . You're printing first two (or three) "child" pages under each "subchild" page found under children of "/mypage/" ("cat" pages). (Edit: and leaving all divs open.) So, what is the output you'd like to see with the page structure outlined above? (Edit 2: Fixed my examples...) (Edit 3: Really fixed my examples... It's not my day.)1 point
-
feldtypepage only.have tamplate if u.set ones in feild setting but if u did1 point
-
This is kind of related to this issue and this commit at GitHub: it sounds like Fancybox has problems affecting IE10 and since Fancybox is being replaced by Magnific Popup in 2.4 these issues should be solved at that point. Another question entirely is whether it's worthwhile to fix Fancybox issues in current (stable/master) PW release.. Oh, and no worries, Joe; your IE-situation is very familiar1 point
-
Those empty items you're seeing are indeed the repeater's "ready items" like Mats pointed out. But while that filter works for you now, I wouldn't rely on the date being empty: when building a test case I changed some formatting options for the date field after already having created some events and ended up in a situation where the dates weren't empty for the pre-existing events. So I'd recommend filtering by the status to exclude unpublished items (filter("status=1")). But this is only a work-around as we're dealing with a bug here. A bug that raises its head only when certain conditions are met. Like you're saying, the extra items appear only after sorting by "eventdetails.date". To be more specific, the items appear whenever the PageArray is being filtered or sorted with a selector using a field inside the repeater. What's even more interesting is that this only happens for "untouched" repeaters. If the repeater contents is referenced in any way before filtering this actually works! OK, this is getting weird enough. I'm filing a bug with some instructions for Ryan to reproduce this odd behavior. I'll edit this post and add a link to the issue a bit later. Edit: See the issue here for some more details: https://github.com/ryancramerdesign/ProcessWire/issues/2751 point
-
As someone who spent years recording translations for corporate and TV productions I can say unequivocally that German is a beautiful, precise joy of a language. But WHY oh WHY is it so bleedin long!!!!! When translated properly (and we used the best translators around for spoken languages) it was regularly 30% or more longer than the English version. And to make things worse, because the subject and object can end up the other way around, if we had a very fast cut video, we could be saying the wrong thing in the wrong place, as it were. Not to mention that in German you at the end of the sentence the verb put! Why? Is it to build up tension or something??? The solution, if we had no elbow room, was to use shorter sentences, and simplify the script, though often at the expense of any poetry, sadly. Thankfully, we also had wonderful voice overs like the gentlemanly Wolf Kahler (a regular on the voice circuit) who with his glorious rolling R can turn even the most castrated German translation into gold!1 point
-
Felix, it'd be great to find a way to get your articles in English versions too, perhaps published on your own site or here. I think there's a big audience that could benefit that might otherwise miss it due to not knowing German (and the imperfect Google translations). Though the same could be said for translating to any other language too, but I perceive ability to read English is a common element among most of our users. Though it does seem like most of our audience reads German too... I think I may be one of the few here that doesn't.1 point
-
InputfieldCheckbox does actually support use of an alternate value for a checked or unchecked value (i.e. Yes/No), but you won't see it except in FormBuilder or in your own usage of the Inputfield. That's because FieldtypeCheckbox does not support different values for these. The reason is that they all map to 0 or 1 in the database, and I think it could get confusing if people start thinking of checkbox fields like text fields when it comes to searching/sorting, etc. So from the development sense, it's best to think of a checkbox field as a boolean or on/off toggle, and you can determine what the on/off state means from your code. This also makes it easy to translate for multi-language support, i.e. echo "Likes spicy food? "; echo $page->spicy ? __('Yes') : __('No'); Okay it's early in the morning here and I'm going back and reading your question again and seeing you mean within the context of locked fields and I see what you mean (appearance of "1" in editor just isn't so useful). I suppose we could always have FieldtypeCheckbox's formatValue() function translate the 0 or 1 to some other text (this is essentially what formatValue is for, though not typically used in admin setting). I'll keep thinking on this, it might be a good idea.1 point
-
If the template where the pdf's are stored is not viewable by the guest role, then you can set $config->pageFileSecure to true. Then only roles that have view permission to the template are able to access the files directly.1 point
-
I would fully expect those guys to come up with a pretty implementation for matrix fields. After all, aren't they the ones that wrote the EE matrix fields plugin? I think that matrix fields make good eye candy, and provide a quick n' dirty way to solve some things in lieu of real structure. But I don't think they are great for the long term or large scale. I'm much more interested in creating timeless tools with well defined data formats and structure, and separating our clients from getting involved with defining schema. I can see the solution presented there being a bit of a monster as the format of data becomes more ambiguous than a rich text field (chances are it actually isn't much more than a rich text field from the storage end). Chances are that data can't be indexed, searched and plucked field-by-field the way ProcessWire's repeaters can. But I haven't actually used it, so maybe I'm making assumptions from what I see on that page. Such things would certainly be possible in ProcessWire, but I'm just not convinced it's right. I can see why the Craft guys are doing it, because they are trying to sell stuff and candy sells. Whereas we're trying to make the best, most sustainable tools for the long term and large scale... the meat and potatoes rather than the candy. So something like this from Craft is not something to "catch up" to, because their bottom line is to make candy you will buy, not on providing what's really the best. My full time job is to develop web sites and applications that use ProcessWire (rather than to sell you something), so I'm simply not interested in colorful gadgetry and instead want the best foundation of quality and substance, at least when it comes to the core. Matrix fields and repeaters are somewhat at odds with that goal (even ours to some extent). These types of fields should be used occasionally and sparingly, for specific purposes. As it is now, I don't personally use repeaters very often. Half the time that I see people using them, they are being used in situations when the person really would have been better off without them. So I'm not so enthusiastic about pushing the core further in encouraging use of repeater/matrix type fields, when I don't personally use them very often, nor do I often recommend them. Don't get me wrong though, I do like candy too (sparingly), but really want to limit it in our core. When you get down to the core, Craft doesn't hold a candle ProcessWire. But I'm always glad to support whatever people want to build as 3rd party modules, and ProcessWire is a good engine for this.1 point
-
ProcessWire 2.4 (2.3 dev) also has the ability to install modules, check for updates, and and update modules individually, pulling from the modules directory. It uses the same method as ModulesManager (actually Soma's code for the most part). But ModulesManager has a nice advantage in that it can check for updates on all your installed modules at once.1 point
-
2.4 is not PHP name-spaced. I got started with it and realized it was going to create headaches for many web developers having to namespace all their template files (not to mention modules). This is extra baggage that most of our audience would not appreciate. So I've put it off to one of the next versions when I can find a way to do it that doesn't require gratuitous verbosity to people's template files. I think that's possible with a built-in template compiler, but that's a bit more work than I was looking to get into for 2.4. If for some reason that doesn't work out, then we'll pen the namespace change to PW 3.0 when a major version would be more amenable to an upgrade that may require changes to one's template files.1 point
-
If new posts are working and not old posts, then it definitely sounds like a directory permissions issue. Most likely the directories represented by the old posts are under a different account ownership than the new ones.1 point
-
I actually have been working on a module called Lister that does much of this. Though it's not yet quite as flexible as I'd like it to be for release, so I'm mostly using it in my own projects until I can get the time to take it all the way.1 point
-
First off, I really think that what you are looking for is just multiple branches in your site tree, one for each language. You don't really need any language support modules installed for this. This is a pretty good way to go when you have the needs you've indicated. When your navigation needs are going to be significantly different across languages, multiple trees is probably the best way to go. But if you want to stick with language support and multi-language fields, then it looks to me like the LanguageSupportPageNames module (included with core dev branch) already does what you are trying to do. My understanding was that the main issue you ran into is that you have instances where you don't want the default language to be active. A couple ways to accomplish this would be 1) just consider the default language to be not in use (don't link to the default language version of any pages, and don't let the user choose that language); or 2) add your own "disable default language" checkbox to every page template and check for it when outputting navigation, etc. Basically, I think there are a lot of very simple solutions if you use the tools that are already there.1 point
-
Thanks for posing this Kyle! A few things to mention: For even more security with the activation code, you might want to use something completely random that isn't influenced by the username. We have something built-in that will do the trick: $p = new Password(); $hash = $p->randomBase64String(100); // 100=length of string See here how it works: https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/Password.php#L154 (code is originally from Anthony Finta's password_compat library). Make sure that you are using $sanitizer->pageName("username"); for your username sanitization. Using $sanitizer->text(); is not adequate for sanitizing usernames or any selector values. In your function that checks for duplicate usernames, check for duplicate emails as well. When you check for users or emails do $users->get("name=$username") rather than $users->get($username); as this will ensure it's checking for only the username, and not potentially confusing a numeric username with a user ID. I recommend using $input->get->var rather than $_GET['var'] because the $input->get version makes it so that you never have to worry about PHP's magic_quotes setting. Last thing to mention is that it might be good to include what type of fields the user_real_name and user_activation are. I believe these are supposed to be text fields, but wasn't sure (especially for user_activation) until later.1 point
-
should be // create a text input $field = $modules->get("InputfieldText"); $field->label = "Name"; $field->attr('id+name','name'); $field->required = 1; $field->attr("class" , $field->attr("class") . " myclass"); $form->append($field); // append the field to the form required also adds a class... Happy experimenting.1 point
-
Don't count on the editor though. Make sure you are sanitizing at the server side with HTML Purifier. Rich text editors like TinyMCE and CKEditor don't do any server-side sanitization (they can't, since they are JS apps). So while it may look like they are sanitizing and validating, they can be bypassed easily.1 point
-
You're in luck http://modules.processwire.com/modules/markup-htmlpurifier/1 point
-
The prefered, simpler way is to make the user when created via API unpublished: $user->addStatus(Page::statusUnpublished); See cheatsheet addStatus Then the user can't login yet. And the admin can just go and publish the user (same as with pages) in the admin. Users are pages so the page API applies here same way as it is for pages. Or using API to publish $user->removeStatus(Page::statusUnpublished); See cheatsheet removeStatus The different system flags are also on the cheatsheet.1 point
-
I will put some thought into this and come up with a more official roadmap to place on the site. Thanks, Ryan1 point
-
@martinluff: I don't agree with you there: I think what we need is clear roadmap [with important modules support], so we can do some of the functions ourselves. Pretty much all requests here have meaning, but Ryan cant run around and say yes to everything, that's just not possible.1 point
-
We've got something on the roadmap for providing this alternate view into pages. I think there are a lot of situations where it will be helpful. For instance, seeing a list of the most recently updated pages, regardless of where they are in the site structure. Or viewing all unpublished pages (like you indicated), or viewing all pages that match a given selector, or have a specified field, etc. The list goes on. So just wanted to let you know this is part of the plan. It will be an alternate tab off of the Page List view, where you can choose that channel-type view when it suits your needs better than the map view.1 point