-
Posts
17,307 -
Joined
-
Days Won
1,725
Everything posted by ryan
-
Looking a little closer, I think the simplest solution will be for you to extend InputfieldImage.module, creating a new module. The module won't need much code in it. It'll just have to override two methods (outlined below). I've included some sample code in this message and it's written in the browser and untested. So you may have to adjust it and play around a bit to make it work. Unless you want to also create a new Fieldtype, you'll need to work within the data available to FieldtypeImage, and that means just a single 'description' field. You'll use that 'description' field to hold an encoded version of multiple fields. I would suggest using JSON (with PHP's json_encode() and json_decode()) or XML, whatever you prefer. But here's an [untested] example of the two methods you would override in your new module that extends InputfieldImage.module: <?php protected $descriptionTemplate = array( 'your_field1' => '', 'your_field2' => '', 'your_field3' => '', // or whatever you want ); protected function renderItemDescriptionField(Pagefile $pagefile, $id, $n) { $description = json_decode($pagefile->description, true); if(!$description) $description = $this->descriptionTemplate; foreach($description as $key => $value) { $description[$key] = htmlentities($value, ENT_QUOTES, "UTF-8"); } $out = <<< _OUT <label for='your_field1_$id'>Your Field #1</label> <textarea id='your_field1_$id' name='your_field1_$id'>$description[your_field1]</textarea> <label for='your_field2_$id'>Your Field #2</label> <input type='text' name='your_field2_$id' id='your_field2_$id' value='$description[your_field2]' /> <label for='your_field3_$id'>Your Field #3</label> <input type='text' name='your_field3_$id' id='your_field3_$id' value='$description[your_field3]' /> _OUT; return $out; } Then you'll also need to override ___processInputFile with something like this (example): <?php protected function ___processInputFile(WireInputData $input, Pagefile $pagefile, $n) { $changed = parent::___processInputFile($input, $pagefile, $n); $id = $this->name . '_' . $pagefile->hash; $description = $this->descriptionTemplate; $description['your_field1'] = $input['your_field1_' . $id]; $description['your_field2'] = $input['your_field2_' . $id]; $description['your_field3'] = $input['your_field3_' . $id]; $description = json_encode($description); if($description != $pagefile->description) { $pagefile->description = $description; $changed = true; } return $changed; } Once you've created and installed your new module, you'll select it as the "Input field" in field's settings, for your image(s) field. You'll also want to make sure that you set it to "no" for entity encoding the description field, in the field's settings. The main drawback of this approach is that you'll need to decode the fields from the image's description field every time you want to access them. So if you are iterating through some images in your template, you'd do it like this: <?php foreach($page->images as $image) { // decode the description field to an array $description = json_decode($image->description, true); // if there's nothing there, then skip it if(!$description) continue; foreach($description as $key => $value) { // you decide if this is necessary for your intended use (usually I would say Yes) $description[$key] = htmlentities($value, ENT_QUOTES, "UTF-8"); } echo "<p>Field 1: $description[your_field1]</p>"; echo "<p>Field 2: $description[your_field2]</p>"; echo "<p>Field 3: $description[your_field3]</p>"; } We can get around this drawback by implementing a hook to do this for you once a page has finished loading. However, if it's that important, I would suggest looking at creating a new Fieldtype instead, as that would be ultimately more efficient, and probably easy to do. If you want to take that approach, let me know because you won't need to do any of this encoding/decoding, instead we'll just have the Fieldtype's DB schema keep the fields instead. So with that approach, the corresponding Inputfield would be a little different.
-
Jasper, I didn't want to leave you empty handed, especially after you've tried this a few times and my suggestions didn't work. Here's an updated version of the ImportPagesCSV module that supports file and image filed importing. It supports both single and multi-file fields, so there aren't any limitations in that area. https://github.com/ryancramerdesign/ImportPagesCSV To import a multi-file field, place each filename or URL on it's own line in your spreadsheet, OR separate each by a pipe "|", OR separate each by a tab (you decide) – basically, you are delimiting the filenames/URLs within the field. In my own tests, I used the pipe "|" to separate the URLs and all seemed to work well. Of course, if there is only one image/file, you don't need anything other than the filename or URL (no delimiter necessary). I ended up changing quite a bit of code, so please let me know if you run into any error messages or anything – it may not be perfect yet, but hopefully close.
-
The field wasn't really designed for that particular use, so there currently aren't instructions on how to do that, but it's certainly possible (and probably not too difficult). But there isn't any easy answer to this question short of modifying the existing Fieldtype/Inputfield or creating a new one that extends it. I imagine that we'll have this built in eventually.
-
Sorry, I neglected to think about that before (how pages have to be created before you can add images to them). One possible way around it is to try to first import without the image field, then import the same spreadsheet again but with the image field (updating the existing pages that were created). You'd need to choose the option to "modify existing page." But it's possible that might work.
-
Thanks–fixed. Old school uploading should work now too. I also made some additional updates for keeping track of max number of files. Original message with the file AjaxUpload2.zip. If you've already installed the previous one, these are the files that changed in the latest version: /wire/modules/Inputfield/InputfieldFile.module /wire/modules/Inputfield/InputfieldFile.js /wire/core/Upload.php
-
Attached is the completed AjaxUpload, though I'm sure there are still a few small tweaks. The attached zip has all the files that need to be replaced in your PW install (organized by PW's dir structure). In this version, after you upload, messages and errors are reported back for each file. Also, if PW changed the filename, you'll also see the status indicate the final filename. For an example of an error message, try to upload a non jpg/gif/png file to an image field. It also works with ZIP files! If your file field and platform support ZIPs, then drag in a ZIP and it'll extract all the files and show them to you. (As far as I know, PW's zip file support doesn't work on Windows… though someone correct me if I'm wrong). Files uploaded go through the same path as regular uploads, so things like max image resizing (at upload time) also work. Please give this a try and let me know if you run into any errors. I'm hoping to get this bundled into PW 2.1 this week. Once I get confirmation from a couple people that all works good on their end too, then I'll go ahead and commit to the source. Antti-- also want to get your eye on all my changes to the JS and make sure all is good. Please make any updates as you see fit. Thanks, Ryan AjaxUpload2.zip
-
I'm curious to know what you find here. I had to add this to your JS in order for PW to recognize it as ajax: xhr.setRequestHeader("X-REQUESTED-WITH", 'XMLHttpRequest'); Should I be having PW core detect the presence of ajax by some other method? Here's how it currently does it: $config->ajax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'); For the code I'm working on here, I settled with keeping the headers method you are already using. I don't know the non-jQuery ajax syntax well enough, and it sounds like we can't send separate POST vars anyway, so might as well just stick with the header. Though PW will check POST vars as a secondary option if there is no header. (I'll worry about things like checkboxes when and if the issue ever comes up). For now, stick with the HTTP_X_FIELDNAME. I'm still working on other updates here, but hope to post soon. Thanks, Ryan
-
Sounds great, I look forward to seeing it. As promised, here's a full example of a simple contact form. This is bare bones, but safe. I've left out spam prevention measures, which I'll be happy to follow-up with if you'd like. Below is an entire template file. I figured it was simpler to show this way rather than splitting into multiple files. Though when forms get really large, I tend to split them in multiple files (and include them). But for smaller forms, I do it like the example below. /site/templates/contact.php <?php $sent = false; $error = ''; $emailTo = 'nikola@company.com'; // or pull from PW page field // sanitize form values or create empty $form = array( 'fullname' => $sanitizer->text($input->post->fullname), 'email' => $sanitizer->email($input->post->email), 'comments' => $sanitizer->textarea($input->post->comments), ); // check if the form was submitted if($input->post->submit) { // determine if any fields were ommitted or didn't validate foreach($form as $key => $value) { if(empty($value)) $error = "<p class='error'>Please check that you have completed all fields.</p>"; } // if no errors, email the form results if(!$error) { $msg = "Full name: $form[fullname]\n" . "Email: $form[email]\n" . "Comments: $form[comments]"; mail($emailTo, "Contact Form", $message, "From: $form[email]"); // populate body with success message, or pull it from another PW field $page->body = "<h2>Thank you, your message has been sent.</h2>"; $sent = true; } } if(!$sent) { // sanitize values for placement in markup foreach($form as $key => $value) { $form[$key] = htmlentities($value, ENT_QUOTES, "UTF-8"); } // append form to body copy $page->body .= <<< _OUT $error <form action="./" method="post"> <p> <label for="fullname">Your Name</label><br /> <input type="text" id="fullname" name="fullname" value="$form[fullname]" /> </p> <p> <label for="email">Your Email</label><br /> <input type="email" name="email" id="email" value="$form[email]" /> </p> <p> <label for="comments">Comments</label><br /> <textarea id="comments" name="comments">$form[comments]</textarea> </p> <p><input type="submit" name="submit" value="Submit" /></p> </form> _OUT; } // include site's main template which outputs everything include("./main.php");
-
I don't think a multi-image field will work, but a single image field may very well work if you want to try it. To try it, backup your PW database and site first. If it doesn't work, you want to be able to restore to where you were. Though, chances are you won't have to do any kind of restoring files, but you can never be too safe. Next, make sure you are dealing with a single image field. Edit your field (in Setup > Fields) and make sure it's "max number of files" is set to "1". Next edit the ImportPagesCSV.module file and locate this (near the top, and add the lines indicated at the bottom). <?php protected $fieldtypes = array( 'FieldtypePageTitle', 'FieldtypeText', 'FieldtypeTextarea', 'FieldtypeInteger', 'FieldtypeFloat', 'FieldtypeEmail', 'FieldtypeURL', 'FieldtypeCheckbox', 'FieldtypeFile', // add this line 'FieldtypeImage', // add this line ); Save, and try it out. Let us know if it worked?
-
Wow that's surprising... rather bloated for what it does. On the other hand, every one of their demos has loaded fast and I would have never guessed about the file size. So maybe it's not the issue that it appears to be at first, given that it's for admin rather than public users. I'm just thankful for browser JS caching. When it gets down to it, all web-based rich text editors seem problematic for one reason or another. It's always a compromise… just the nature of the beast I guess.
-
Great example, thanks for posting it. There are definitely some things I like about that approach. The only problem is that it's static. You can't go back and make changes directly to the form (without copying and pasting the whole thing, or parts of it again)? And if you've customized the markup further, then copying and pasting may then be out of the picture. Still, seems like a worthwhile compromise and it really may be the best way to go. But I see this approach as being one more aimed at people that already know how to build their own forms and are just using this as a convenience. So this is one area where I'm still leaning towards more automation and less markup control, just to keep things dynamic, and within reach of clients. But providing the copy/paste markup like this seems like a good option to provide regardless.
-
Glad you got it working. Thanks for posting the final code.
-
You are right. Looks like I must have had the PageLinkAbstractor plugin installed when I last saved those pages, and they ended up in the recent DB update. I'll re-update today. Thanks for finding this.
-
Pretty cool! Somehow I completely missed that, thinking it was a background image or something. Nice, I've not experimented with the multi-column stuff... looks interesting.
-
Thanks I have updated for 2.1 and placed on GitHub: https://github.com/ryancramerdesign/FormTemplateProcessor Somewhere around ProcessWire 2.3 we'll be including a formal form builder. Not yet sure if it's going to use the same approach as this one. This can be used for public facing forms. But the person creating the forms should be an administrator in PW (whether the developer or the client).
-
Not sure I understand? Looks like this is one giant field to cover the entire page. Pretty impressive with the 3 columns actually. That's not something I'm used to seeing in HTML. Definitely not something I've seen in TinyMCE. This 1-giant-field for the entire page is probably not something you'd see much of in the real world, beyond a demo. Aloha seems pretty useful even if just used for multiline fields. Though it'd be great if it had some option to place limits on the markup a user can use, for single line fields at least. But I don't see anything like that, looking through their site. We can always just strip the block-level stuff.
-
Shane, glad that did the trick! Thank you for your inquiry about donations, that's very nice of you. We don't have anything like that at present, but maybe will set it up someday. I certainly don't expect people to donate anything. But if they are wanting to, time donations are always appreciated. Time can mean anything, whether blogging about PW, sending the occasional tweet, helping out others on the forum, linking to processwire.com, writing PW modules/templates/code to share, helping to find and nail bugs, getting involved in the code, etc. So I guess that translates to anything you are interested in towards improving the project or sharing it with others. But of course, nothing is expected or required.
-
It sounds like you've now got both the first() added and the single image fields. You want one or the other, not both. The first() was just to grab the first image from an image array. If you have the field set to contain a max of 1 image, then it's just going to have that image, and no array. So if you are going to keep the "first()" in there, then change it to a multi-image field (set the max to 0 or greater than 1). If you want to keep it a single image field, then get rid of the "->first()". If it still doesn't work, we need to take a closer look because the error message you posted sounds like work_thumb may not be a variable on the page (or there may be no image attached). One thing you can do is: var_dump($web_work->work_thumb); Just to see what it is. I'm guessing it's null, and it's coming from a page with no image attached. Another thing you might want to do is place some more limits on your $pages->find(). Right now it's pulling all pages with the work_web template, no matter where they are. There's no problem with that, but it might be pulling a page you've forgotten about somewhere else in the tree. I would suggest something more specific: $work = $pages->find("parent=/work/projects/, template=work_web, sort=-date"); Or: $work = $pages->get("/work/projects/")->children(); // assuming all children use work_web template Or: $work = $pages->get("/work/")->find("template=work_web, sort=-date");
-
I've just depreciated the Textformatter::format($str) function in favor of Textformatter::formatValue(Page $page, Field $field, $value). I guess I didn't consider the things we'd be using Textformatter for in the future. But it should be ready to go now. Just grab the latest commit and implement the 'formatValue' version rather than the 'format' version in your Textformatter module. You can now get the field name from $field->name. I see what you mean, though am surprised they don't provide built in capability to deal with single-line (titles) vs multi-line (textareas) markup. We could always strip paragraph and heading tags from the single line fields. So long as they are both dealing with the same kind of markup tags, I think we'll be fine here. Though not positive. I'm excited to see how this goes! Thanks, Ryan
-
I'm not sure how to reproduce the first issue you brought up. I've tried several times dragging trees into the trash and out again, but no luck. Please let me know if you are able to reproduce it again at some point. I was able to reproduce the second issue you brought up, which was a loss of status when trees as trashed all at once. It would just give them all a "trash" status, removing any previous unpublished, hidden or locked status they may have had before. I've just fixed this in the latest commit. Thanks for finding it! Sorry for the lost status in your tree. Btw, it can sometimes be dangerous changing stuff in the DB directly, outside of PW's API. It sidesteps several other things that occur when a page is saved. There are other tables involved in every $pages->save() so manipulating the data directly, even a simple parent change or status change, can cause problems. Not major problems, but still, it's best to try and make the change from the API. And if that still doesn't do it then post here and we'll figure out a safe solution.
-
Shane, it sounds like you have a multiple-images field rather than a single image field. Two ways you can solve it. First would be to convert to a single image field. Go in Setup > Fields, and edit your work_thumb (and work_full) fields. On the 'details' tab of each, enter "1" for "maximum files allowed". That will make your field dereference in the manner your code is written, making your code example work how you'd expect. The other solution is for you to change the first line in your foreach() to this: $image = $web_work->work_thumb->first(); You may also want to add a check to deal with pages that don't yet have an image attached, i.e. if(!$image) continue;
-
I'm not sure which solution we're talking about, because there have been a few posted. Can you post the code for the solution you were using? I'm guessing it would be an easy fix, but just need the context. The above will only cycle through the first 16 images on any page. Then it would move on to the next page in your $photos->children loop and display the first 16 photos from the next page. But it's not going to do anything for pagination. If you want to keep things from getting overly complex, I'd recommend either focusing on paginating the images from a single page (like the example below) or paginate multiple pages where each page has 1 image. I think we can find straightforward solutions for either of those. <?php $limit = 16; $start = ($input->pageNum-1) * $limit; $images = $page->images->slice($start, $limit); foreach($images as $image) { // ... }
-
Beautiful site Martin! Nicely done! Love the transparency on the trees, and the trees as a concept for your company name as well. You really have a fantastic portfolio here too. Thanks for posting this.
-
I can post one on Tuesday when I'm back in my office. I'm just on mobile till then.
-
No doubt we'll build this auto-publish or auto-unpublish as a module this hooks into LazyCron. When built, it will most likely be a core module, but one that's disabled by default.