-
Posts
17,258 -
Joined
-
Days Won
1,710
Everything posted by ryan
-
The file fieldtype doesn't carry a fulltext index on the filename, but it does on the description. See if this works: report_color|report_style|report_file.description~=$s
-
I'm guessing one of those fields doesn't support the ~= operator -- What type of fields are: report_color, report_style and report_file?
-
I tried doing a test locally using "title|body~=white" and it worked for me on pages titled "white" as well as "white/blue". So the next thing to look at may be the fields you mentioned. What type of fields are report_color, report_style and report_file? All text fields? If report_file is a file field, you probably need to do report_file.description, otherwise it's searching the filename. Another thing to look at is the word and how MySQL is treating it. Is it at least 4 characters? Is it a stopword? MySQL has some limitations with fulltext indexes that make them really useful for searching sentences, paragraphs and documents, but less useful in some other instances. Though all can be adjusted in MySQL's settings. Though the only adjustment I've ever had to make to MySQL regularly is to set it to index words down to 2 characters rather than just down to 4 characters. Regarding stopwords: With fulltext indexes, MySQL doesn't index "stopwords", defined as words that are extremely common and not unique enough for search purposes. These are words like: and, get, thus, than, and a hundred or so others. Though "white" does not appear to be a stopword, so I don't think that's the issue. But if one of the stopwords appears in your selector that uses a ~= operator (or *= with a single word), the word is not used in the search .. unless custom stopwords are configured in MySQL and PW. The full list of stopwords can be found here: http://dev.mysql.com/doc/refman/5.5/en/fulltext-stopwords.html
-
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.