Jump to content

ryan

Administrators
  • Posts

    16,715
  • Joined

  • Last visited

  • Days Won

    1,516

Everything posted by ryan

  1. And I've started to do it (the section for WireArray is now updated). The system Soma put together here is fantastic. Yes it can. Though I think $pages->add() is mainly useful without going to far on the fields there. I still find the regular syntax (populating the field values directly to the $page object) the most readable. I'm a little confused, as there aren't any parallels between MODX and ProcessWire in this regard. Though if ProcessWire were to stop evolving, then maybe that would be a parallel with Evo? (though glad to hear others are working on continuing Evo). No plans to stop evolving here. Switching to PDO, then namespaces and composer support is part of that evolution. This evolution is important for ProcessWire to grow and ensuring it remains the best tool for the job. All ProcessWire upgrades are optional of course. You don't have to upgrade unless you want to. I'm still running Photoshop CS3. ProcessWire is a big enough software that some changes will be more valuable to some than others, depending on what you are doing with it. As ProcessWire evolves, sometimes modules that want to support it will also have to evolve. As for now, FormBuilder is the only module I'm currently aware of that had to be updated in order to keep working with this version. That's not really a surprise, as FormBuilder is probably the most complex PW module out there. There may be more, but none that I've come across yet. What I'm much more shy about is doing anything that would require changes to one's site templates. I see API syntax as locked for changes, but not additions. We would version the API if any major syntax changes were ever necessary. So upgrading from one version of PW to another should rarely if ever require changes to your own site templates, unless your site templates are doing some very low level stuff. As for server, PHP 5.2 was EOL'd by the PHP team more than 3 years ago. They are no longer updating it. Meaning, none of us should still be using it, at least not for current projects we are maintaining or keeping up-to-date. Trying to maintain PHP 5.2 compatibility through future versions would be a drag on the project and people's usage and perception of it.
  2. What version of PW are you running? I'll assume PW 2.3 stable unless you say otherwise. I think you may be right about the editable() check though. Though it looks to me like the module is performing the correct check. I might need to re-think a hook in FieldtypeRepeater to Page::editable. For now, try pasting this at the top of your /site/templates/admin.php: wire()->addHookAfter('Page::editable', function($event) { if($event->return) return; $page = $event->object; if($page instanceof RepeaterPage) { $event->return = $page->getForPage()->editable(); } }); Let me know if that fixes it?
  3. It doesn't support repeaters. If you want to create new forms that don't already exist on the site, then you need to have some kind of administrative access. It does support access control for administrative users though, enabling you to have various levels of administration. For example, you could have a user that can browse entries, but can't edit the form. I'm not sure I totally understand, but if that user role has some kind of access to the admin, you could assign whatever FormBuilder permissions you wanted to them. But keep in mind that administration of forms is really intended for administrators. Hidden fields are supported. Hooks are also supported (like in the rest of ProcessWire), enabling you to modify what gets populated to a field before it gets saved. There is no "edit mode" except to administrators. When a user submits a form, they can't come back later and change their answers, for example. It may be possible but I can't say for certain. I would suggest sticking with whatever code your payment provides gives to you. You could always experiment with it to see if you can make it a FormBuilder form, but I wouldn't depend on it. Payment processors will probably want you to use their code.
  4. Without knowing the full details of your context, you mentioned you are using pagination: I would suggest checking if you need to add a "start=0" to your selector that retrieves the listing of pages for your sidebar.
  5. You'd only want that if you were planning to set the page number yourself from it. ProcessWire doesn't recognize any GET variables in the core. The most valuable presence of that variable [for me] is as a flag that I need to turn on page numbers for the template. Is your template calling render(); on any other pages? Are you using URL segments? Are you setting any of the MarkupPagerNav options manually? What other modules are in the system? There are factors that could feasibly come into play, so I'd need to know everything that's happening in order to say for sure.
  6. It looks like your URLs are lacking trailing slashes. I would try to enable trailing slashes and see if that fixes the issue. I only set my templates to omit trailing slashes for certain instances, like for a /sitemap.xml template, for example. I've not done extensive testing of the language-support modules on templates that are set to exclude trailing slashes, so it's possible there may be issues there.
  7. I've got TinyMCE 4 working with PW locally on my dev branch. They've changed quite a lot on the API side, but it all seems like improvement even if it does require lots of changes to code that uses it. In some ways it seems like a different product. I need to put more work into supporting all the other options we currently support in TinyMCE 3, but so far TinyMCE 4 is looking very good.
  8. It actually shouldn't matter whether it's in a repeater or not. Repeaters don't change the type of any fields. But your code above has "->->" which looks like a typo? The nice thing about repeaters is that they really aren't anything more than a regular PageArray like any other. An alternative is to set $user->language to the language you want the field to return its value in, before you retrieve the value. Then return $user->language back to the language it was before.
  9. I've pushed and update to the dev branch so that sorting should now work across languages. Previously, calls like these would still result in the returned pages being sorted by the default language field, regardless of the user's language: $pages->find("..., sort=name"); $pages->find("..., sort=title"); $pages->find("..., sort=pageref.name"); $pages->find("..., sort=pageref.title"); // and so on To demonstrate the problem, lets say that you had these three pages: /numbers/one/ /numbers/two/ /numbers/three/ In Spanish, those pages would be named: /numeros/uno/ /numeros/dos/ /numeros/tres/ Lets say I executed this in English (my default language): $pages->get('/numbers/')->children('sort=name'); The result would be alphabetical: /numbers/one/ /numbers/three/ /numbers/two/ If I executed it in Spanish, the order would still be the same, sorted by the English spelling (which is clearly not correct): /numeros/uno/ /numeros/tres/ /numeros/dos/ They should be sorted alphabetically by Spanish instead. With the latest commit to the dev branch, they should now sort correctly for the given language. Meaning the Spanish results would now be in this order: /numeros/dos/ /numeros/tres/ /numeros/uno/ The scope of those goes beyond page names. This also affects multi-language text fields. So if you've got a multi-language 'title' field for instance, you can sort by that, or any other multi-language field you are using, and the sorting should work properly now. It does not yet work with language-alternate fields, though I think it's probably unusual to use those fields as sorting keys anyways.
  10. I think the issue is that you were specifying "comments.text" rather than just "comments". You don't need to specify a subfield when searching comments. This should already work (and it is implemented in 2.3): $pages->find("comments*=SomeStringHere, sort=-created"); There isn't actually a "text" field in the DB, which is why your search wasn't working (it's called 'data' instead). I have gone ahead and pushed an update to the dev branch that looks for ".text" and substitutes ".data", so that nobody else should run into that issue.
  11. Same thing this time. It's odd, I've not ever seen a PDF do this before.
  12. Backwards compatibility is always the concern with changing stuff like this. But we actually have FieldtypeConcat which provides a way of achieving the same thing.
  13. What module? I'm thinking this is MarkupPagerNav, but want to double check. I can't think of any reason why you'd have to allow page numbers in the child page, unless you are doing some of your own page renders that themselves do pagination: $child->render(). Is your template calling render() on any other pages? Might be good to see the template code where the issue appears, as well as your code that outputs the pagination.
  14. It's hidden in the admin interface unless you've got advanced mode on. I've tried to keep the admin as simple as possible so that people can think of templates and fieldgroups as one in the same thing. But the reality is that they are actually separate things. The benefit of having them separate is that you can have multiple templates sharing the same group of fields. But currently we're not highlighting that behavior on the admin side just because I think there is more benefit to the clarity of templates just being a single thing. i had always thought we'd expand on the behavior on the admin side in giving people more options, but the need seems rare enough that it's stayed in advanced mode for now. Probably what I will end up doing is making the API itself abstract the behavior too, so that it adds a like-named Fieldgroup automatically when you access $template->fields and one isn't already there.
  15. See the cheatsheet documentation at http://cheatsheet.processwire.com/ and click the "advanced" button, then click "WireArray/PageArray". All the methods for WireArray are at your disposal for this. Specifically the section on "Setting/Modifying Items" is probably the most helpful. A WireArray only carries one of each item, so if you add/insert/etc. an item that's already present, it'll move it in the array rather than add another copy.
  16. I never was able to reproduce this before. Can you paste in the characters that aren't working for you? I will try to paste them in some pages and then test it out. Also check that you are using the %= operator in your autocomplete settings with the field (not positive that's necessary, but it does bypass the index in case there are any indexing issues with greek characters).
  17. I agree, it does look very nice! I look forward to integrating this into ProcessWire.
  18. I didn't realize before that PageLinkAbstractor doesn't work in this scenario, so will have to put some time into correcting that. But for now I think the best bet is to just search/replace your DB dump when migrating it from dev to live (and this is what I do regardless).
  19. 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.
  20. How is the pagination segment "page2" ending up in the path? The page number isn't considered one of the URL segments returned by $input->urlSegments, so it shouldn't be showing up in there unless the "allow page numbers" option is turned off for that template.
  21. I think Antti is right here that the lightbox plugin would need some feature enabling it to load it's own images (ajax or otherwise) to go beyond what's actually present on the page. What you have here are two different systems of pagination. I am wondering if you could trick the lightbox into it–you could render those first 15 images as you are now, but then render links for the remaining (perhaps hidden to the user) but have your lightbox plugin somehow recognize them as part of the gallery. For example: <a class='gallery' href='photo1.jpg'><img src='photo1thumb.jpg'></a> <a class='gallery' href='photo2.jpg'><img src='photo2thumb.jpg'></a> ... <div style='display: none;'> <a class='gallery' href='photo16.jpg'><img src='1pixel.gif'></a> <a class='gallery' href='photo17.jpg'><img src='1pixel.gif'></a> ... </div>
  22. We have 3 cats, and two of them are into singing. Your cat sounds like our cat Sasha. I'm thinking the gateway if() might be here. That $numFields variable must be greater than 1 since your JSON response says "multiple fields". Yet I think you want it to be 1. And it looks that could happen if HTTP_X_FIELDNAME wasn't set for one reason or another, here. I don't understand the technical details of how Fredi works yet (though hoping to learn soon), but I do wonder if this could be solved by just sending the ajax post request to ProcessPageEdit only, rather than Fredi? The reason is that it seems like if something is hooking into ProcessPageEdit, that Fredi doesn't call, wouldn't get executed. An example is this line in FieldtypeRepeater, which I think is attaching a hook that doesn't get executed via Fredi. One other thing, unrelated, is that it looks like these lines should be moved above the ajax section in your execute() function? // Check if there is not such a page found if ( ! $this->pageContext->id) throw new WireException("Page not found"); // Check that this page is editable by current user if ( ! $this->pageContext->editable()) throw new WireException("You don't have right to edit this page")
  23. I think that the "page::path" needs to be "Page::path" (uppercase first character). Also, where you place this will matter. You want hooks to be attached before any other code executes. I like to use the $config->prependTemplateFile = 'init.php'; in my /site/config.php, and then setup hooks or any common functions I want in /site/templates/init.php.
  24. I can't seem to see anything from the cheatsheet PDF. It just shows up as gradient lines where text would usually be. Anyone else get this? See the screenshot.
  25. TextWrangler is great. While I use VIM and PhpStorm for code, I use TextWrangler for everything else. It's great for performing big manipulations fast (sorting, finding, replacing via regex's, duplicate line processing, multi-file manipulations, etc.). This is one tool I could not do without.
×
×
  • Create New...