-
Posts
17,151 -
Joined
-
Days Won
1,668
Everything posted by ryan
-
The ~= and *= assume wildcard operations in selectors. They can be used for searching text, textarea and related fields. The ~= operator says to find all the words in the given copy (not necessary together), and the *= says to find the given phrase in the copy. The ~= operator assumes wildcard matches with any of the words you provide, so a search for "apple" will also match "applesauce", "applet" and "apples", and likewise for any other words in the selector. The *= operator is more restrictive in that it's looking for your words in a specific order. But if searching for only one word, both operators would produce the same result and work with partial matches. Where they differ is when your search includes multiple words. MySQL does not support wildcards with indexed content beyond this. But it does support more selective wildcards with non-indexed LIKE operations (with the "%" and "_" wildcards). We don't use those in ProcessWire at this time because they are very slow in MySQL. In fact, too slow to suggest they be used for everyday operations. LIKE operations require full table scans, so are not a good thing to hide the implementation details of in ProcessWire. However, you can still use them if your circumstance calls for it. Here's an example searching the title field using a LIKE operation: <?php $result = $this->db->query("SELECT pages_id FROM field_title WHERE data LIKE '%juice%"); $ids = array(); while($row = $result->fetch_assoc()) $ids[] = $row['pages_id']; $matches = $pages->getById($ids); That would return pages with a title field matching "juice", "applejuice", "orangejuice" and "juices". ProcessWire selectors can match "juices" from "juice", but can't match "applejuice" or "orangejuice" from "juice" because of the way MySQL fulltext indexes work ... the match has to start from the beginning. But performing a LIKE match is a slow process, so something I recommend avoiding unless the scale of usage is under your control. So while I agree with you that additional wildcard selectors would be nice, we can't go much further without abandoning MySQL for searches and using something like Lucene (which is written in Java).
-
How to handle video upload or integration with youtube/vimeo etc...
ryan replied to Sylvio's topic in General Support
A single textarea should be able to accommodate multiple embeds (at least, that's what I do). But if you want to keep them separate (which woud probably be more bulletproof for client use), setup a separate child page for each embed. Then your video page would just cycle through it's children to pull as many video embeds as it needs. To make it even more bulletproof for the client, make a separate video_embed template and set it to be the predefined template that is used when adding children to your video page (under Setup > Templates > Your Template > Advanced). -
The specs on what is considered a valid URL are apparently very broad. I've had the same experience in being a little surprised at what PHP's filter_var URL filtering allows. But apparently it is based on a defined ISO (?) standard. If you put some extended ASCII or accented characters in there, you'll see the URL filtering get involved. We may want to implement a more defined URL filter specific to just http/s (perhaps as a configuration option for this fieldtype). Also double check that you have relative urls turned off in the field's configuration, as it may help in this particular case (though not yet at a computer to test).
-
How to handle video upload or integration with youtube/vimeo etc...
ryan replied to Sylvio's topic in General Support
Embedded videos are easy: just create a textarea field and don't add any textformatters to it. Then the client simply pastes in the YouTube/vimeo/etc. provided embed code into that field on the page. All you have to do is output it in your template. For client uploaded videos (non embedded) you just create a regular file field. Your means of output in your template will depend on the video format and what you do with it. I usually advise clients to use an embedding service because it makes it so darn easy, and bulletproof. If you don't want YouTube/etc branded videos, there are some very good an inexpensive commercial video embed services that work the same way but tailored to you (I think screencast.com is one). However a regular file upload field in PW will be just as easy if you know the details of your video format and targeted player. -
Peter, looks good but not sure your uncacheAll() is doing anything here since the pages are already cached in $reports (PHP's garbage collector isn't going to unset them as long as there is a reference to them). But if you are running up against a memory limit, try placing a limit on the $reports: <?php $start = 0; $limit = 500; do { $reports = $pages->find("template=report, start=$start, limit=$limit"); if(!count($reports)) break; foreach($reports as $r) { $r->setOutputFormatting(false); $r->report_status_select = "123456"; $r->save(); } unset($reports); $pages->uncacheAll(); $start += ($limit-1); } while(1); Written in the browser, so code may not be perfect. Let me know if you still run up against any memory limits. Also in your earlier example: $c->client_status_select = $selectpage->id; You can also do just this: $c->client_status_select = $selectpage;
-
Sounds good, let me know if any issues turn up again.
-
Are these examples still not working? You may want to double check that your copy of PW is relatively up to date with the current source. If in doubt, you can always replace the /wire/ directory with a new one (along with /index.php and /.htaccess). Also, you may want to edit /site/config.php and set the line that says "$config->debug = false;" to be "$config->debug = true;". That will turn on stronger error reporting that can help a lot during development.
-
Where is this code going? Is it part of a template or used somewhere else? In templates, PW has something called outputFormatting turned on (unless you turn it off). Internally, all file/image fields are stored as arrays. But the file/image fieldtypes use this output formatting to convert a file array to a single file when you set the max files to 1. This is provided as a convenience for your templates. It's so that you don't have to think about arrays when they aren't relevant to your intended use. I've been assuming you are using this code in a template, but if you are using it somewhere else (like via bootstrapping PW separately) then that outputFormatting isn't going to be on by default. So I figured I should double check that we are talking about code in a template, just to make sure we're talking about the same thing? The other thing to look at is that the file/image field is actually populated. I didn't do that in the example, but here's how you would: <?php foreach($page->children as $artist_item) { $image = $artist_item->artist_image; if(!$image) continue; // no image, so abort $thumb = $artist_item->artist_thumbnail; if(!$thumb) $thumb = $image; $thumb = $thumb->size(100, 100); echo "<li><a rel='lightbox' title='{$artist_item->title}' href='{$image->url}'><img src='{$thumb->url}' alt='{$artist_item->title}'></a></li>"; }
-
Let me know what you want to do with the TinyMCE config, and I can help you determine what needs to be put in. If you find a better solution for a RTE than TinyMCE, let me know. I've experimented with quite a few, and as annoying as it can be, TinyMCE seems to be the most tolerable. Also, lightweight markup languages (like Markdown) are often a good alternative. The results they produce tend to age and scale better... if you can convince your client to adopt the syntax.
-
Adam, Good find. If you issued a get() or find() that includes a "parent=" portion in the selector that didn't resolve to a page, then it would return the homepage. This was due to an error in the PageFinder code that didn't differentiate between 0 (homepage's parent) and null (no parent). This has been fixed and the update committed to GitHub. Thanks for finding this. Ryan
-
Sorry my code example assumed we were dealing with a single image (due to the field name being 'image' rather than 'images'). I should have thought to post an example for both. If your 'image' and 'artist_image' fields are designed just to hold a single image, I would recommend converting them to that to reduce confusion. To do this, edit those fields, and set the "maximum files allowed" to 1. After you do that, the API will reference it as a single image rather than an array of images. Following that, the original code example I posted should work. If you want to keep them as multi-image fields, then you'd want to change that code example to this: <?php foreach($page->children("limit=32") as $folio_item) { $image = $folio_item->image->first(); $thumb = $folio_item->artist_thumbnail->first(); if(!$thumb) $thumb = $image; $thumb = $thumb->size(100, 100); echo "<li><a rel='lightbox' title='{$folio_item->title}' href='{$image->url}'><img src='{$thumb->url}' alt='{$folio_item->title}'></a></li>"; } The only difference between the above example and the original are the first two lines in the foreach(). They grab a single image out of the array, like this: $folio_item->image->first(), rather than just $folio_item->image. This is the same as doing eq(0) as in Adam's example, so use whatever syntax you prefer. @adamkiss: thanks for your replies here!
-
You are very close! The main issue that I see is that you are referencing $image in a context where it doesn't exist. See my comment in your code: <?php foreach($page->children("limit=32") as $folio_item) { if($folio_item->artist_thumbnail) { $img = "<li><a rel='lightbox' title='{$folio_item->title}' href='{$image->url}'><img title='{$folio_item->title}' src='{$thumb->url}' alt='{$folio_item->title}'></a></li>"; // $image is an uninitialized variable in the line above. Did you mean it to be $folio_item->image? } else if($folio_item->artist_image) { $thumb = $folio_item->artist_image->size(100, 100); // you could also solve it by just moving this line below above the "if" statement: $image = $folio_item->artist_image; $img = "<li><a rel='lightbox' title='{$folio_item->title}' href='{$image->url}'><img title='{$folio_item->title}' src='{$thumb->url}' alt='{$folio_item->title}'></a></li>"; } // Output the image echo "$img"; } Here's how I might recode it: <?php foreach($page->children("limit=32") as $folio_item) { $image = $folio_item->image; $thumb = $folio_item->artist_thumbnail; if(!$thumb) $thumb = $image; $thumb = $thumb->size(100, 100); echo "<li><a rel='lightbox' title='{$folio_item->title}' href='{$image->url}'><img src='{$thumb->url}' alt='{$folio_item->title}'></a></li>"; }
-
Looks like that is just a PHP notice because PW is in debug mode. But I did confirm there is an uninitialized var there. I think this may be my mistake. I have submitted a pull request to apeisa with a correction for this. I'm guessing that /about-us/ is already an active page on your site? Since you've already got a page living at that URL, that page is handling the request rather than the redirects module. To do that redirect, you'll want to edit that page's template and do the redirect from there, i.e. <?php $session->redirect("history/"); But that's not particularly reusable. I know on some sites, it is a common need to have a section page (like /about-us/) redirect to the first child page. If that's your need, you may just want to setup a new template called section-redirect (or something like that) and do this: <?php $session->redirect($page->child->url); That way it's reusable for similar needs on any other section page. Lastly, lets just say you wanted a generic "redirect" template that you could use on any page to redirect to any other URL. You'd want to create your template called "redirect" (example) and create a new field of type "URL", giving it a name like "redirect_href". Add your "redirect_href" field to your "redirect" template. Edit your "redirect" template to have code like this: <?php $session->redirect($page->redirect_href); Then set the "about-us" page to use your "redirect" template. Edit it and type in the URL you want it to redirect too, like "/about-us/history/", in this case. Then you can continue to reuse that redirect template anywhere else that you might need an existing page to redirect elsewhere. The value of the Redirects module is that it will handle redirects for pages that aren't in your site tree. But if the pages are already in your site tree, and you want them there, then you'd want to use one of the methods described above rather than the Redirects module.
-
I totally agree. The funny thing is that this feature was actually in Dictator CMS (ProcessWire from 2003). It was designed in part by the needs of a company intranet, where they had documents for employees about benefits and stuff. I'm not sure we can easily set it up at the field-level just because asset storage is currently provided at the page-level, and fields just get their asset storage location from their parent page. Plus, we already have a means of determining if the file should be protected: if a page lacks the "guest" role, then we can assume that it's files should be protected. That's because any page that lacks the "guest" role requires a login to access. So when a page is protected, it's asset storage dir would start with a period, i.e. /site/assets/files/.123/ rather than: /site/assets/files/123/ I'm thinking we'd do that rather than the /files-private/ mentioned in the previous message just because it strikes me as a littler simpler (simpler is better). PW's htaccess file already blocks access to any dirs that start with a period. But we'd update it so that requests that match /site/assets/files/.[0-9]/ would get sent to PW, which would perform the access checking before delivering the file's contents.
-
Sounds good! I look forward to seeing what you come up with. Also will be having some new updates in ProcessWire over the next few weeks that I think you'll find interesting too. I'm working on multi language and user system updates, and expanding upon what you can do with using pages for data storage at the same time.
-
Release: New Admin Theme [digital] + 3 new ways to edit content
ryan replied to Adam Kiss's topic in Themes and Profiles
Good explanations! You sold me. I will have to make this my new admin theme. Now I'm really curious why Akismet flagged my reply to Peter a few minutes ago as spam, and didn't flag your message considering all the spam triggers mentioned in your last paragraph... -
I was going to say to type "title body filefield.description" into the search fields in Modules > Process > Page Search. But went and tried it myself and see we're using a multi selection field rather than a text input. So I went ahead and changed it to a text input so that you can use subfields (like filefield.description) for searches. If you grab the latest commit, you should be able to configure the Page Search module to use filefield.description for admin searches. https://github.com/ryancramerdesign/ProcessWire/commit/1cc0c0549d1f55fb380211037dc267be10b0b71a For your own searches, you can already do this just by including filefield.description in your selector. For example, this would look for a match in either title, body or filefield.description: $matches = $pages->find("title|body|filefield.description*=something"); If you start getting a whole lot of fields in your selector, you might get better performance out of bundling all the fields you want to search into a FieldtypeCache, and then searching the single cache field rather than the other individual fields. You can already do this. ProcessWire will let you select a field for automatic sorting as long as it has the "autojoin" option set in the field's configuration. So if the field you want to sort by isn't showing up in Children > Sort Field, then chances are that it's not set for "autojoin" in the field config. Go ahead and check that autojoin box and let me know if that solves it? Thanks! Ryan
-
Release: New Admin Theme [digital] + 3 new ways to edit content
ryan replied to Adam Kiss's topic in Themes and Profiles
I just installed [digital]. Well played and nice design... but is it really necessary to have such abrasive background music for an admin theme? I mean, good thinking, but I'm just not sure how I feel about singing admin themes. I could also do without the pharmaceutical ads and popups, but I guess that's what AdBlock is for... I just didn't expect to have to use it for a CMS admin theme. The contextual text ads randomly showing up in the Page List were a nice touch, but personally confusing to me. However, I am intrigued by your "live help" chat window. Though I don't think it's working because when I typed a question about TinyMCE in there, it apparently connected to some chat room for older folks discussing topics I won't repeat. Needless to say, they weren't very helpful. So while I like the idea, I'm not so sure about the usefulness of the execution. If you can fix these issues I think you'd have a great admin theme. ;D -
What are the field types you are trying to add to the search? The text search in the admin can only search fields that are indexed for fulltext searches. This includes text, textarea, cache and I believe a couple others. But of course all data in ProcessWire is searchable, but that search box in the admin is designed purely for partial-match text searches. It would be fairly simple to modify or extend the admin page search process if you are interested, I can guide you through it.
-
You are right, that would make sense. See the latest commit, it contains updates to the FieldtypeURL/InputfieldURL so that it reports errors as you would expect. Note that it still saves the page, but it will now at least tell you about the error. I'll be adding an additional javascript validation option for Inputfields once we enable required fields. Thanks, Ryan
-
Currently all files attached to pages are stored in /site/assets/files/[page_id]/. If someone has a URL directly to a file, there is nothing to prevent them from accessing it. Down the road, I figured we would add another dir, like /site/assets/files-private/, and those requests would get sent to PW (via the htaccess) rather than letting Apache handle them. PW would determine whether to passthru the file data based on whether they have access to the page. There is significant overhead in doing this (depending on filesize), so it's not something we'd want to do on other pages.
-
You don't need to worry about moving the files to the proper place. Just set it to the path or URL where the file is located, and it'll take care of it for you. <?php $page = new Page(); $page->template = $templates->get("your-template"); $page->parent = $pages->get("/path/to/the/parent"); $page->save(); // a page has to exist before you can add files to it // add a file to a single file field: $page->filefield = "/path/to/file/somefile.pdf"; // or, add a file to a multi-file field: $page->filefield->add("/path/to/file/somefile.pdf"); // don't forget to save it again $page->save(); You could also do this if the file is somewhere else online: <?php $page->filefield = "http://some-domain.com/some-file.pdf"; In all of the above examples, ProcessWire will copy the file to it's own storage location behind the scenes. I will look at what we can do to make that name field optional or automated.
-
Peter, In that case, it's not working quite how I'd planned. Now that we've got an example of this scenario, I was able to update it to work. https://github.com/ryancramerdesign/ProcessWire/commit/570f18127dda799c5352669f7df86c40fbf2d2f5 Grab the latest commit, or just that file if you prefer. Just tested here, so hopefully it will work there too. Let me know. Regarding an optional 'name' field... this is considered the one common element for all pages and any other objects in ProcessWire to have. Maybe we can auto-populate it with something if omitted. Are you adding these files manually or via the API? Thanks, Ryan
-
5000+ files would be more than you'd want to put on a page, just because it would be difficult to manage from an administrative standpoint. So I think your approach with pages is fine. I'm just hoping you are adding all these files with some automated API functions rather than manually. So it sounds like the main thing is how they appear in the admin page list? If that's the case, we can easily change what appears in the page list. By default the page list displays the title field (if there is one) and otherwise displays the name field. You can modify that behavior by going to Modules > Process > Page List and editing the fields to display. You can display a field specific to your files template, and it'll get ignored by all the templates that don't have that field. So here is what I think you want to do: Go to Setup > Fields > Title. Uncheck the "global" option, so that your files template can exist without a title field (optional, if you want it to). Go to Modules > Process > Page List. Change the "name of page field to display" to: filefield.basename title Replace "filefield" with the name of your files field. I'm also assuming that your file field is a single file, and not multiple files. I've not tried doing this with file fields before, but I think it should work.. let me know what you find. Thanks, Ryan
-
Peter, There isn't currently a way to do that directly, but there are some alternatives. It would help me to understand the context of your need. What's the field you want it to generate from? To disconnect name+title: You could uncheck the "global" option on the title field, and that would prevent it from appearing on the "add page" screen, which would basically disconnect title and name. In that scenario, you'd be forcing the user to enter a name for a page independently of anything else. You could hook into the $pages->save() function and automatically set the page name for new pages (those that don't have an ID yet). You could create your own Process module for adding pages, perhaps extending ProcessPageAdd. Then edit /admin/page/add and select your Process rather than the default. You could also setup another page and Process for adding pages of a specific type in your admin. There are other options too. What approach is best probably depends on the situation... tell me more and we can figure it out. Ryan