-
Posts
17,231 -
Joined
-
Days Won
1,697
Everything posted by ryan
-
When using PW's API, you should always consider your code to be operating as a kind of superuser, just like in PHP. In find() operations where you are retrieving multiple pages that you don't know exactly what they will all be, it's a sensible default to exclude "hidden", "unpublished" and no access pages, unless you request otherwise. This is there as a matter of convenience and pagination, not security. Of course you can override that (when you want to) with the "include=hidden" or "include=unpublished" or "include=all" options. Whereas with get() you are being very specific about what you want–a single specific page. Otherwise why would you get() it? Neither find() or get() are intended as a primary means of access control–we have other methods for that (see below). They are methods setup to operate in the most common use cases and keep your API calls as short and simple as possible. Just because find() filters out hidden, unpublished and no-access pages by default does not mean you should count on it for access control. That's because the pages excluded from a find() don't include runtime access control, just that which is stored in the DB. Further, the behavior of whether or not a no-access page shows up in a find() result (that isn't overridden with an include= directive) is configurable with template access settings. Granted, in most cases find()'s defaults are giving you exactly what you want in terms of excluding pages the user can't view (for your convenience), but that's not the entirely of PW's access control, which supports runtime hooks. PW's job is to provide access control for the request, but not for your own code, that's the developers job. PW intends to give you, the developer, access to everything (like you would with jQuery and the DOM), and you decide whether or not it should be available for output. PW provides you with some handy access control methods to help with this: $page->viewable(); // is the page viewable? true or false $page->viewable('field_name'); // is the field on page viewable? true or false $page->editable(); // is the page editable? true or false $page->editable('field_name'); // is the field on page editable? true or false If you want to have you own get() and find() that operate under different defaults, this is easy to do with hooks in your /site/ready.php file. For instance, this would add a $pages->one("selector"); method that automatically does a viewable() check for you and returns a NullPage() if the page is not viewable: $pages->addHook('one', function($event) { $page = $event->object->get($event->arguments(0)); if($page->id && !$page->viewable()) $page = new NullPage(); $event->return = $page; }); Would there be value in adding a method like the above to our $pages API by default? Maybe. It wouldn't benefit my own API use, because the only time I use $pages->get() is because I want to get something without conditions. But if it would be super handy for others I'm happy to add it. Here's another example, lets say you want a method in $pages, like $pages->all("selector"); that always returns all pages with "include=all" implied: $pages->addHook('all', function($event) { $event->return = $event->object->find($event->arguments[0], array('include' => 'all')); });
-
Makes sense to me, I'll move that <?php endif; ?> down one line, so that the name/version only appears when logged in.
-
Testing here with PW 2.7.2 in a new URL field I setup called "href", I used the URLs you mentioned. For my field settings, I have "Allow single/double quotes" set to true, and for "Text formatters" I have "HTML Entity Encoder" selected. I tried with and without the "allow IDN" option, but it doesn't matter here since we're not testing with IDNs. Here are the results I got: https://en.wikipedia.org/wiki/Peter_O'Toole Input to URL field in admin: https://en.wikipedia.org/wiki/Peter_O'Toole API code to output: echo "<a href='$page->href'>test</a>"; Output in rendered page: <a href='https://en.wikipedia.org/wiki/Peter_O'Toole'>test</a> Result: Clicking the link works, taking me to the page on Wikipedia https://upload.wikimedia.org/wikipedia/commons/5/53/Peter_O'Toole_-_1968.jpg Input to URL field in admin: Input to URL field in admin: https://en.wikipedia.org/wiki/Peter_O'Toole API code to output: echo "<img src='$page->href' />"; Output in rendered page: <img src='https://upload.wikimedia.org/wikipedia/commons/5/53/Peter_O'Toole_-_1968.jpg' /> Result: Picture of Peter O'Toole Basically, it's working exactly how it should. My best guess is that it wasn't working for you because you've got some other code in there somewhere HTML entity encoding the URLs, to make up for the bug prior to 2.7.2 where text formatters weren't being properly applied to URL fields. Another possibility, check if your $page possibly has output formatting turned off? It would need to be ON for this all to work. That's interesting, so it looks like the URL is getting URL encoded, converting the apostrophe to a %27. I did try entering that too, but PW converted it back to an apostrophe and then entity encoded it, resulting in the same working output as in my second test above. If this is literally how your URLs are stored in the database, then my best guess is that when you are outputting the value, either the $page's output formatting is off for some reason, or the HTML entity encoder wasn't selected in your "text formatters" details tab, which would prevent a URL with an apostrophe from working, whether it was URL encoded or not. I would suggest upgrading again to 2.7.2 and double check all your settings, especially the one about allowing single/double quotes and the Text Formatters. If the URLs are still not working, then check to make sure in your template file that the page's output formatting is enabled, like this: if($page->of()) { echo "<p>Output formatting IS enabled</p>"; } else { echo "<p>Output formatting IS NOT enabled</p>"; } If it's not enabled, you'll want to track down where you are turning it off, typically with a $page->of(false); or $page->setOutputFormatting(false); Finally, check that you don't have something else entity encoding the URLs in your site. If you've got a line like this, you'll want to remove it: $page->bfd_image_from_url = htmlentities($page->bfd_image_from_url); // avoid this
-
BFD what's an example of the exact URL as you have it input in the admin page editor, and what's an example of the exact output you get in your source on the front end? For your field settings, what textformatter plugins are being applied (details tab), if different from before? You mentioned the URLs were working before, when actually they really shouldn't have, so I'm wondering if they might be getting double encoded somewhere along the line. If some of your URLs are input encoded and some not it might be that you need to output the value a little differently on your front end to account for that. But I need to know what the exact inputs and outputs are first.
-
I'm waiting for the coffee to kick in still, so this probably is missing something but I'll throw it out there anyway... text_field*=cat|dog, page_field=1234|4321 Btw, for some of the solutions above you can also leave out the "foo=" part if you want too. You only need to start naming the OR expressions if there are multiple OR expressions that should be evaluated as part of separate groups. But if you need a "bar=" too, then you'd need to name them.
-
Tom, sorry that field was behind a showIf dependency for the inline edit fields checkboxes, like Adrian mentioned. It's actually only supposed to apply to those checked fields, which is why it didn't appear. I was replying from mobile before and was forgetting this. That particular setting really is only meant to apply to those checked fields, so your $page->edit() wasn't working as a result of a bug, which I have pushed a fix to 3.0.2 just now. You should now be able to use $page->edit() with any field regardless of page. There's no concern about performance hit here. The reason it's recommended off is only as a default setting. For instance, let's say you've got a "summary" field in your page and you are rendering search engine results that include that summary. You probably don't want the summary to be editable in all those search engine results, whereas you do want it to be editable when you are actually on the page. So the setting is just there to reduce confusion since chances are, most of the time you'll only want to have a field editable when you are on the page it is owned by. None of this is meant to apply to options B through D since you are already in control of it all from the API side. I don't think there's much we can do about it, if that image is not part of your field there. However, if it's a concern, you may be able to add something like this to your css file to adjust the cursor: #your-container img.your-image { cursor: pointer; }
-
Tom, check your PageFrontEdit module settings page to make sure you've got the option enabled to allow editing of pages other than the current. This is a new option added in 3.0.2. previous versions let you edit anything anywhere, whereas this version let's you lock it down a little more, and it comes that way by default. but you can turn it off from the module settings page.
-
Go to your URL field settings (Setup > Fields > your field) and check the box to "allow single/double quote characters in URLs". That should fix it. We started not allowing those characters in URLs by default because such URLs could be a security problem if someone forgets to enable the "HTML entity encoder" text formatter for their URL field, and happens to output the URL in an href attribute.
-
I'm not entirely sure I know how to answer all your questions here because it sounds like you may trying to do things with InputfieldFile is may not necessarily be designed for. If that's the case, you may be better off extending it as a new PHP class, or copying its code to new module, rather than trying to achieve these all with hooks. Another thing I'm not sure about is whether you are talking about a front-end or back-end context. If dealing with a front-end context, the ajax uploading will not work. In some cases you may have to disable it on back-end use too (see the commented line below for how to do that). InputfieldFile is really meant to be used in combination with FieldtypeFile and within the page editor. But it is possible to use it outside of that context. Though you will still need to supply it a Page object so it has a known storage location, but the given Page doesn't need to have a files field. Meaning, it can be any Page, even an admin one. Here's an example of how you might use InputfieldFile on it's own: // page the file will be stored with (doesn't have to have a files field) $myPage = $pages->get('/path/to/your/page/'); // optionally set the name of existing file(s) that will be present (or leave it blank) $myFiles = array( $myPage->filesManager->path . 'myfile.txt' ); // file extensions you allow $myExts = 'pdf csv txt'; // -------------------------------------------- // create the form $form = wire('modules')->get('InputfieldForm'); // create the files field $f = wire('modules')->get('InputfieldFile'); $f->name = 'my_files'; $f->label = 'My Files'; $f->extensions = $myExts; $f->overwrite = true; // $f->noAjax = true; // uncomment if necessary $pagefiles = new Pagefiles($myPage); foreach($myFiles as $filename) { $pagefile = new Pagefile($pagefiles, $filename); $pagefiles->add($pagefile); } $f->attr('value', $pagefiles); $form->add($f); // add a submit button $f = wire('modules')->get('InputfieldSubmit'); $f->attr('name', 'submit_form'); $form->add($f); // ------------------------------------------- // process the form if(wire('input')->post('submit_form')) { $form->processInput(wire('input')->post); $pagefiles = $form->get('my_files')->value; foreach($pagefiles as $pagefile) { echo "<p>Your file: $pagefile->url</p>"; } }
-
You can use "|" to OR fields, or OR values, but not expressions. Your selector is translating to something you didn't intend. I think the selector you might be attempting is instead this: template=event, enddate>=2015-11-06, enddate|startdate<=2015-11-13 Or you could use OR-groups: template=event, enddate>=2015-11-06, (enddate<=2015-11-13), (startdate<=2015-11-13) Either of the above selectors says: The template must be event. AND The enddate must be greater than or equal to 2015-11-05. AND (The enddate must be less than or equal to 2015-11-13 OR the start date must less than or equal to 2015-11-13).
-
Allow translators to edit Admin->Setup->Laguages->$LANG
ryan replied to maba's topic in Multi-Language Support
Correct, if you've given them edit access those templates. With page-publish installed, that means the user must have that permission to publish any content to the live site. Editing an already published page enables one to publish live content. So that means they can't edit an already published page. That behavior is correct. On the other hand, they would be able to edit unpublished pages (or create them, if you've allowed that). Correct. That's what you'd want the hook for. Alternatively you could add page-publish permission for that role just to the "language" template from the Access tab of the template editor (see "Additional edit permissions and overrides"). But since you aren't otherwise managing access for the language template, I would suggest just using the hook function as the best solution. In that case, you'd want to modify the hook function to consider the language page-edit permissions: wire()->addHookAfter('Page::editable', function($e) { $page = $event->object; $user = $event->user; if($page->template == 'language' && $user->hasPermission('lang-edit')) { if($user->hasPermission("page-edit-lang-$page->name")) $e->return = true; } }); -
Aaron, PM me your FormBuilder key and I can reply with a snippet of code that will do it for you.
- 20 replies
-
If you upload a random txt or html file to your web server, can you access it at the other domain? My guess is yes. If so, it sounds like an honest mistake. Perhaps you are on a dedicated IP and the owner of the other domain made a typo when setting up their DNS record. Or perhaps the web host made an error when setting up their VirtualHost directives in Apache. You should be able to correct the problem by adding this to your .htaccess file somewhere after the "RewriteEngine On" line: RewriteCond %{HTTP_HOST} !^www\.yourdomain\.com [NC] RewriteRule ^ http://www.yourdomain.com/ [L,R=301]
-
Good debugging work. The reason this occurs is because MySQL has a limit on the length of a return value from GROUP_CONCAT, though I think that limit is configurable in the MySQL server settings. The GROUP_CONCAT is only used for multi-value autojoins, so not something you need to be concerned about with large text fields or the like. Though with anything large, it's best not to use autojoin at all since it forces PW to load that data in memory every time the page is loaded. It might mean you could only load a few hundred pages in memory at once rather than a few thousand. Autojoin can be a nice optimization for things like "title" or a short "summary" field, or a blog post with category page references. But you would only want to use autojoin for a field that you know will always be accessed from a given $page, every time you load it, regardless of where you load it. For everything else you should leave it off.
-
Thanks guys, I've added an additional check for this. Regarding the use of a cropping string like "50%,40%" to the size() method, does this work? It doesn't seem to do anything for me. The capability is one that was added from a PR a long time ago, and one I've not ever had the occasion to use in production. But just testing it now, it doesn't seem to do anything at all other than return a resized image without cropping? The $options['cropping'] = '50%,40%' just resolves to a string of '50%,40%', whereas it looks to me like your intention is to provide an array to the size() method. Wouldn't it be better to do one of the following? // just provide a string $page->image->size(200, 120, '50%,40%'); // provide an array $page->image->size(200, 120, array('cropping' => '50%,40%'));
-
Allow translators to edit Admin->Setup->Laguages->$LANG
ryan replied to maba's topic in Multi-Language Support
If page-publish permission is installed, it is required in order to edit already-published pages. I suppose we could override that for Language pages if the user has lang-edit permission, but not sure we should, will have to think about that one more. However, if you want to provide that behavior for your site, you could do so with a hook in your /site/ready.php file: wire()->addHookAfter('Page::editable', function($e) { if($e->object->template == 'language' && $e->user->hasPermission('lang-edit')) $e->return = true; }); I agree, I have committed a slight modification that enable this (now on dev). These changes are minor enough and restricted to one permission (lang-edit) that it doesn't affect anything else, so it's fine. -
Allow translators to edit Admin->Setup->Laguages->$LANG
ryan replied to maba's topic in Multi-Language Support
@maba turn off access control for the language template, as I think it may be interfering with the lang-edit permission. Next make sure that the appropriate roles have the permission "lang-edit" (which I think would include all of your translator roles?). They should also have "page-edit" permission in their role, but that role doesn't need to be assigned to the language template because the lang-edit role is superseding it. I also recommend using language page-edit permissions if you aren't already. Meaning, your main "translator-de" role should have page-edit-lang-de permission, your "translator-ru" role should have page-edit-lang-ru permission, and so on. If your "translator" role is the one that can edit default language, then it should have page-edit-lang-default permission. I also recommend assigning your translator roles page-edit-lang-none permission, so that they can edit non-multi-language fields, such as the site/core translation files. Also, don't rely on the "who an access this page" fieldset on the settings tab for this particular case because the lang-edit permission is superseding the existing access control (for language template only). This is similar to the user-admin permission. You'll want to test by logging in with one of the translator accounts. -
Determine old vs. new value of field when saving
ryan replied to Jonathan Lahijani's topic in Modules/Plugins
Nope, it would give you the same copy that you already have. Unless something cleared the page cache between the time you loaded $page and the time you did your $pages->get(). PW clears the page cache after every save() or delete(), so if you found it was working in your case then chances are there was a save() that occurred after you loaded $page, but before you tried to retrieve $oldPage. -
Determine old vs. new value of field when saving
ryan replied to Jonathan Lahijani's topic in Modules/Plugins
That's correct. PW tries really hard not to keep multiple copies of the same page in memory at once, which is why you have to make it force-reload a fresh copy from the DB if you want to know what the page looked like before changes were made to it. -
$user in /site/config.php in older version PW 2.2.17
ryan replied to Raymond Geerts's topic in General Support
I missed that. I read it as 2.6.17 for some reason. That 2.2.17 version should probably be upgraded. -
Determine old vs. new value of field when saving
ryan replied to Jonathan Lahijani's topic in Modules/Plugins
In Martijn's hook, the $oldPage retrieval will return the same exact copy as $page, so it won't be possible to compare them since you'll be comparing the same page instance. What you'd want to do instead is retrieve a fresh copy of the page, then you should have two different instances of the same page to compare: $oldPage = $this->wire('pages')->getById($page->id, array( 'cache' => false, // don't let it write to cache 'getFromCache' => false, // don't let it read from cache )); I think you'll need the dev branch for this, as the 'getFromCache' option is not in PW 2.6.1 if I recall correctly. In 2.6.1 or earlier, I think that the following would work, but is not quite as efficient: $this->wire('pages')->uncache($page); $oldPage = $this->wire('pages')->get($page->id); -
How to translate admin dropdown menu's from a module?
ryan replied to Marc's topic in Multi-Language Support
I'm assuming this is a Process module, since that's the only one that supports nav arrays. The arrays provided in your getModuleInfo (like the 'nav' array) are not called at runtime, instead they are stored in the DB. As a result, there's no reason to make those labels translatable–actually you should avoid it, otherwise the wrong language translation might end up stored in the DB. Instead, just make them regular strings like 'Enter Order' rather than __('Enter Order'). Then, somewhere else in your module, make them translatable. It can even be in a PHP comment. For instance, you could add this at the top of your module file: /* * __('Enter Order'); * __('Enter User'); * and so on... * */ These should be in your 'default' language. Make sure the phrases are identical to those in your 'nav' array. Doing this just ensures that the language parser knows they are translatable phrases. After making that change, do a Modules > Refresh, then go back and translate the file (Setup > Languages > language > your file), and save. Now it should work. If using AdminThemeReno, it won't work, unless you upgrade to the latest dev version. I just fixed that issue in AdminThemeReno yesterday actually. Since it looks like you are using Reno, you'll want to grab the latest dev branch. -
$user in /site/config.php in older version PW 2.2.17
ryan replied to Raymond Geerts's topic in General Support
Also look into using a /site/ready.php file, which will get called once the API is ready, but before any page rendering begins. The file receives all API variables, and you can put whatever you want to in it. There is also a /site/init.php file you can create, which does the same thing, but is called before the current $page has been determined. -
Allow translators to edit Admin->Setup->Laguages->$LANG
ryan replied to maba's topic in Multi-Language Support
@maba I put in some updates yesterday (dev branch) that may provide what you are looking for. After installing the latest dev, click to Access > Permissions > Add New. Click the section to add a new predefined permission, and add the "lang-edit" permission. Then add that permission to the role(s) that you want to be able to access Languages (Setup > Languages). If you are using language page-edit permissions (like page-edit-lang-default, page-edit-lang-es, etc.) then the user will also need to have the appropriate language page-edit permission in order to edit translation files for a given language. Please let me know how it works for you.