-
Posts
16,772 -
Joined
-
Last visited
-
Days Won
1,531
Everything posted by ryan
-
I don't think this sounds like a caching issue. Adam is right, if you are logged in and have edit access, you aren't getting anything cached unless you've cached it yourself manually (using the MarkupCache module). Alan is it possible that any of the pages in question were unpublished or hidden and not participating in the count? If not, I'm honestly not sure what could have caused the tags.count to not work properly in this example here. That particular selector translates to a MySQL count() query, so its a surprising one to fail. If anyone finds that it can be repeated, please let me know and we can fix it. Ouch, this doesn't sound fun. I won't ask you to try and reproduce that one. I'll try from here. Some browsers (Firefox especially) do strange things to forms when you hit reload. Not sure if it's still the case, but Firefox used to advance radio buttons to the next item every time you hit reload in a form. I think some of this can be resolved by setting an autocomplete attribute to off on the <form> tag (and we may need to do that on the form in question).
-
Also wanted to add that you can do this: if($user->language->isDefault()) { // user has the default language } Having a default language is required by the system, but it doesn't matter what language you decide for it to be. However, I would suggest making it whatever language the homepage of your site is in by default.
-
Request Module proposal: DB migration assistant
ryan replied to Rob's topic in Module/Plugin Development
Web sites aren't just databases, but files too (which may be version tied to the database), so I don't see anything that operates just on SQL queries as being realistic. Versioning is one thing (which can be done), but migrating in the manner you mentioned is something else. I don't think you should ever consider "live" as something that can be frozen while you go to work on dev, though I guess that depends on the case. I know I couldn't freeze any of my live sites. Migrating file-based assets (templates, js, css, etc.) is a pretty simple matter. But migrating databases gets more complicated. Future tools for migrating data in ProcessWire will likely take a web-service approach (two sites talking and sharing JSON) rather than one involving sharing of database queries. -
This looks very interesting--thanks for setting this up charliez! I do worry a little about documentation like this, because it steps outside of our public API. I don't consider every function in PW to be part of the public API that folks should use (the majority of it is not). ProcessWire isn't meant to be that low-level of a framework. There are so many components that are really just there to support the public API, rather than be part of it. Looking at the docs in this manner loses all context of that. The cheatsheet really has the right context. I would just suggest that people use our regular API docs (especially the cheatsheet) and then use something like this apigen documentation for zeroing in on more detail about a specific function or class, if they need it. I think the apigen documentation could really be useful for contextual links to more detailed function reference, where applicable (like in links from the cheatsheet). But I don't suggest integrating functions that aren't in the cheatsheet into your projects. The public API in ProcessWire is a constant, but everything else can change with versions. Also, I'm not so sure what I think about this service hosting our documentation (I don't know them well enough yet), so I went ahead and copied it to here: http://processwire.com/apigen/
-
The replacements defined with the InputfieldPageName module are just used in that live javascript conversion. Whereas $sanitizer->pageName uses PHP's iconv() to perform a UTF-8 to ASCII conversion (when the $beautify param is set to true). When the $beautify param is omitted, then it just removes anything invalid, converting to a dash. They don't use the same method because the pageName() in Sanitizer needs to be predictable so that we know it's always going to return the same thing on any installation and at any time. Plus, it needs to be really fast, because it's potentially called hundreds or thousands of times per request. Whereas the one in InputfieldPageName is done as a live translation that you can observe as it does it (and thus can be configurable), and it's okay for it to be slow with lots of RegExps. The consistent behavior with pageName() is actually kind of important to the CSV import module, as the page names are used as a primary key and become a means of determining if something should be updated or created new. Though if you'd never imported pages before, and you weren't ever going to change the InputfieldPageName translation string further, then it wouldn't matter. It sounds like in this case, we need another PHP-based method of converting page names that also does translation, like the JS one. Then you could modify the CSV import module to call upon that rather than $sanitizer->pageName. I'm thinking the PHP based method should probably be defined directly in the InputfieldPageName module, since that module owns the custom page name translation settings. Once in place, we could still make it accessible through Sanitizer perhaps through a new pageNameTranslated function, or something like that.
-
Thanks Rob, got your message and will take a closer look today. Regarding the functions you mentioned: • wakeupValue() converts a file from a basic storage type (typically an array) into it's representation in ProcessWire. Most often this is used to translate the raw value from the DB into the live value for runtime. • sleepValue() does the opposite of wakeupValue() and translates a runtime value back to it's basic type for storage. If you are just dealing with a simple type like an integer or a string that are represented in the database exactly how they are at runtime, then wakeupValue() and sleepValue() don't need to do anything at all (other than return the value they were given). So these functions really only come into play when the field's value has to be stored differently than it would be presented at runtime. This would be the case for anything that is presented as an object at runtime. Since an object can't just be "stored" and still have its components be searchable and sortable in a database, it needs to be translated to/from fields in a DB table. Likewise, if you are sending object field values to/from JSON/XML web services, you probably want that object represented as an array, so that it can be encoded by XML or JSON. • sanitizeValue() is entirely unrelated to the other two functions (though you may see it called in series with them). But it does nothing other than sanitize a value that is assigned to a $page. So lets say that you have a field called 'myfield' and this API call gets executed: $page->myfield = 'my value'; That value gets passed through the sanitizeValue() method for whatever fieldtype is used by 'myfield'. After passing through sanitizeValue() it gets set to the $page. The sanitizeValue() method is just a way to ensure that invalid data doesn't get assigned to the page. So if the fieldtype used by 'myfield' expects it to be a string, then its sanitizeValue() method should ensure that whatever it returns is a string, regardless of what it's given. Or if you want, you can have it throw an exception when it receives invalid data. But here's what a sanitizeValue() method might look like for 'myfield': public function sanitizeValue(Page $page, Field $field, $value) { if(!is_string($value)) $value = (string) $value; return $value; }
-
That's correct, the .htaccess file is blocking access to /site/templates/ (and below), but only for files with these extensions: php, inc, htm, html, tpl. This is for security, since files in there are meant to be parsed by ProcessWire, not direct browser access. As long as its not one of those extensions above, PW shouldn't be blocking it. Though you may prefer to move it outside of PW's templates dir and perhaps into something like /site/tinymce-templates/. I agree with this -- I think it's far preferable to use PW fields for this kind of stuff. It's definitely not a best practice to use something like TinyMCE for keeping structured data. (Though technically, I suppose the markup coming from TinyMCE could still be considered structured data if it's kept semantic.) This approach seems like something that one would do in some other CMS that doesn't have the ability to adequately manage custom fields. I don't understand using the approach here, but I also like to see that this can be done with TinyMCE. I'm sure there are times when this could be handy. I also know that everyone in this thread knows what they are doing and are already familiar with when and where they want to use PW fields. So I'm sure there are good reasons for taking this route. For instance, if you knew you never needed the data to be searchable at the field-by-field level, and didn't need it to be portable beyond the current need, then you might reduce the load of custom fields in your system by taking this TinyMCE template approach.
-
To render or not to render - that's the question
ryan replied to charliez's topic in General Support
Adam, the page render() method doesn't know if it's being called upon to render a page for a request, or being called by the API somewhere else. Bust since the render() method basically just executes your template and captures the output, you can have your template look for some variable that tells it to render a 'thumbnail' version. In this example, I assign a 'useThumbnail' variable with a value of true to each photo page, and then call its render() method: $photos = $pages->get('/example/page/get/')->children('template=photo'); foreach($photos as $photo) { $photo->useThumbnail = true; echo $photo->render(); } Then in your 'photo' template, check for that 'useThumbnail' trigger: $img = $page->image; if($page->useThumbnail) $img = $image->size(150,80); echo "<img src='{$img->url}' alt='{$img->description}' width='{$img->width}' height='{$img->height}' />"; -
Rob, feel free to email to me and I can try out this weekend and hopefully come up with an answer. This is one I probably need to step through the code as it runs. But If you are getting WireArray(0) somewhere, you may want to nail that back to a regular array since that is the value you want to work with. You can get a regular array by calling the getArray() method from any WireArray.
-
Thanks Alan - I'm limited to mobile today but will do more research on that error when I get back to the computer this weekend. Thanks for saving that DB, that may be helpful to determine what happened.
-
Welcome to the forums Ben! I would suggest not using the skyscrapers site profile because that will only work with PW 2.0 and that version is now very out of date and not a good one to use for benchmarking. Though I don't think that has anything to do with the error you are experiencing, but want to make sure you are using an up-to-date version. I do plan to update the skyscrapers profile to work with PW 2.2+, but haven't yet had the time to do it. So for now, I would suggest using PW 2.2 and the basic site profile that it comes with. I've been building a list of people waiting for the PW 2.2 compatible skyscrapers profile and happy to send it to you when it's ready--just let me know. Netcarver: thanks for your great responses here. I'm really impressed with your knowledge on this stuff.
-
Get specific page attributes/fields from pagearray set
ryan replied to Bill's topic in API & Templates
I'm still wondering about this, since it sounds like its not working correctly here. What is the scale of pages in your site using the template 'cool-page' and what auto join fields does that template have? I'm just trying to find out as much info as possible to be able to reproduce it. Not sure I understand the question 100% so let me know if i don't answer it right. The class::method syntax when you add the hook is just a way of communicating to PW that you want to hook all current and future instances. Kind of like a jQuery live() event. This is consistent to how you'd usually refer to a class::method in documentation, outside of a specific instance. If you only wanted to hook one instance then the syntax would be $objectToHook->addHook('method', $myObject, 'myMethod'); and $myObject is most commonly $this. -
Thanks for the follow-up on the solution you found for this.
-
Get specific page attributes/fields from pagearray set
ryan replied to Bill's topic in API & Templates
Thanks Bill, I think the main difference is just PHP5. There is a lot about PHP5 that really benefits the ability to build simpler plugin systems. WP and others are still built around a PHP4 idea of plugins, probably for legacy support reasons. It doesn't really matter much which you use. But here are a couple factors. I definitely like the readability of $this->apiVar better, but the truth is that using wire('apiVar') is more bulletproof. In order to use $this->apiVar, you have to be in a class that extends Wire, and you can't take control over the __get() method in the class. Or at least if you do, you have to make yours call parent::__get() when your class doesn't have a handler for a given variable. So if you are using wire() exclusively, you really don't have to worry about things when you override a __get() method. Also, wire() doesn't have to pass through any comparisons, as it's singular purpose, so technically a little more efficient. Lastly, wire() can be used in procedural functions, and in classes that don't extend Wire, making it portable for use anywhere in your site's code. Still, it may not feel right to rely on a procedural function to access API vars. But if you can get past that feeling, it actually makes a lot of sense to use it. It's kind of like PW's version of jQuery() or $(). Using wire() is newer syntax, and not something you could do in the original PW 2.0. So I haven't standardized on one or the other, and use both interchangeably, and PW will always support both. Also want to note that PW passes all the API vars to your template files, so you don't have to use wire() or $this, and instead you can just access them directly, like $pages. -
TinyMCE content image disappears when editing existing image link
ryan replied to apeisa's topic in General Support
Not a problem Soma. I'm just glad you were able to find a fix for the other issue, because that one was a lot harder to fix than this one. Also, my experience with TinyMCE is that any time I fix something, I break something else, but don't usually find out about it right away. So this just seems to go with the TinyMCE territory. -
I don't know of a way that you can do this at present (short of making a module to do it). But if you need text formatted in a certain way, it's best to split the components of it into separate fields so that you can ensure that any formatting that happens is separated from the content.
-
Field settings when used with/in template not being saved
ryan replied to vitor's topic in General Support
You are right, looks like it's not working with Safari for some reason. Just confirmed. I will put this in the issue queue. Thanks, Ryan -
I think you are on the right path here. The page that Jasper and Marc linked to is good when working with larger scale stuff (and smaller too), but I'm not usually that disciplined on smaller stuff. One alternative would be to bundle your news_posts.inc into a function, and keep a file with that function and any others you might need. I usually call mine tools.inc. The function would look like this: /site/templates/tools.inc function listNews($news) { $out = ''; foreach($news as $item) $out .= "<p>{$item->title}</p>"; return $out; } Your template files that need to list news (or use your other functions) would include('./tools.inc'); at the top, and then they would call the function when/if they needed to list news: echo listNews($pages->get('/news/')->children('limit=5'));
-
Get specific page attributes/fields from pagearray set
ryan replied to Bill's topic in API & Templates
I can't seem to edit my last message without having it convert everything to entities (something not working right with the forum). I just wanted to mention the class line should be this instead: class YourModule extends Wire implements Module { -
Get specific page attributes/fields from pagearray set
ryan replied to Bill's topic in API & Templates
This is not what it's supposed to do. This is probably the most common selector usage there is. Need some more information to determine what's going on here. Try turning on debug mode (/site/config.php) and edit the $config->debug line to be true. That should at least give a better sense of what error is getting thrown. Though if not, tell me more about this case. How many pages are there using 'template=cool-page' and how many 'autojoin' fields are part of it? If you are dealing with hundreds of pages you may want to place a limit=n on it. This looks like a good approach. If you want to add your getAttr() method directly to the PageArray, so that you can call it like this: $IDs = $randomChildren->getAttr('id'); ...you can do it with an autoload module: class YourModule implements Module { static public function getModuleInfo() { return array( 'title' => 'Your Module', 'version' => 100, 'summary' => 'Adds a getAttr() method to all PageArrays', 'singular' => true, 'autoload' => true ); } public function init() { $this->addHook('PageArray::getAttr', $this, 'getAttr'); } public function getAttr(HookEvent $event) { $pageArray = $event->object; $key = $event->arguments[0]; // ...the rest of your code goes here... $event->return = $pageKeys; } } -
Field settings when used with/in template not being saved
ryan replied to vitor's topic in General Support
What browser and version are you experiencing this in? Also note that the way you are changing settings makes it specific only to the template you are editing the field from. If you want to change the field settings outside of that context, you'd change them under Setup > Fields. I'm thinking you already know this, but just wanted to mention it just in case. -
TinyMCE content image disappears when editing existing image link
ryan replied to apeisa's topic in General Support
It looks like this is a new issue that came as a result of our recent fix for the links not being editable in some instances. A text() in jQuery needed to be an html() instead -- easy fix. Just committed. This one I can't duplicate. Though if it was possibly related to the other issue, then that may be why. Let me know if it still does it to you after the other issue is fixed, and if so, in what browser (I tested in Chrome 17). Thanks, Ryan -
Updated to support negative values in the timestamp, and committed. It had to do with validation rather than the DB field type. We're using a MySQL datetime field for storage, so that isn't bound to the limits of timestamps. We're using timestamps just on the PHP side for sortability, sanitization and abstraction from a defined date format.
-
I'm also confused about what the repeater would be here for. If you are wanting to support <title> and <meta description> then I would make two text fields with 255 character maxlength: browser_title meta_description You could make those two global, but I would instead suggest having your templates populate those fields like this: <title><?=$page->get("browser_title|title"); ?></title> <meta name='description' content='<?=$page->get("meta_description|summary"); ?>' /> Using that approach, it'll attempt to use a "browser_title" or "meta_description" field if they are present and populated. If not, it'll default to using the "title" and "summary" field. That way you can add/populate the "browser_title" and "meta_description" fields to your templates as you need them. Otherwise, you'll end up having to populate all of them manually, rather than just focusing your attention on the ones that matter most. I usually keep browser_title and meta_description fields on my homepage template, and templates used by any other major pages (like top level nav stuff). And then it use the title and summary fields for everything else.
-
In that fictional example there are two find() operations, so those aren't going to happen in 1 query, unless the results of 1 are already cached. If I recall, this should work (though not at a place to double check): $pages->find("question.name=yes"); But I want to point out that query counting is usually a waste of time. And I used to do a lot of it, up until I read High Performance MySQL. MySQL will execute a 100 simple queries faster than it will 1 heavy one. So performance usually has much more to do with query quality and proper indexing than query quantity. This is not the way I was originally taught, and not how I worked for many years, so it took me awhile to get it. You can always $db->query() and join the original example into 1 query, making sure that everything happens using an index, but you may or may not see any tangible benefit for your efforts. If there is some real performance bottleneck that could be resolved by querying directly, I still do it, though it's pretty rare. Also note that layers on top of MySQL are not unlike layers on top of languages. C++ is built on top of Assembler, and PHP is built on top of C++. PW is a layer on top of MySQL and PHP. It's possible to make lower layers perform faster than higher layers, if you know your way around them. Every layer is a compromise that has to be compared against the need. I know my way around MySQL and PHP, and for me PW lets me develop stuff 10x (or more) quickly than I could without it... and it's rare that I think it's costing me anything in performance. But if I had a project where maximizing the performance out of MySQL and PHP took precedence over all other factors, then I would keep out all other layers (no CMS, frameworks or other libraries).