Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/03/2019 in all areas

  1. Core version 3.0.137 on the dev branch adds the ability to hook multiple methods at once, in a single call. This post details how it works and provides a useful example of how you might put it to use in your development environment. This version also refactors and improves upon several core classes— https://processwire.com/blog/posts/pw-3.0.137/
    6 points
  2. You could take a look at https://modules.processwire.com/modules/access-by-query-string/. Maybe it'll do exactly what you need, or you could take it as a starting point and tweak it to your needs.
    2 points
  3. Interestingly, I came across this today. https://wptavern.com/jamstacks-growing-popularity-brings-increase-in-wordpress-plugins-for-deploying-to-netlify
    2 points
  4. Actually the API provides access to the hashed password. If this password hash (the one you use for your secure URLs) needs to remain constant, I guess that's as good approach as any – mash some non-public variables together, generate a hash, and then check if the user has provided the correct hash. If you're looking for a ready-made solution I'm not aware of one, but on the other hand this sounds like something you could put together in a few lines of code, so not really a massive problem. The specific implementation depends on how your site is built, but technically you just need to add a bit of code somewhere before any markup is rendered – check a GET param from $input->get->token_var_name, and then compare that to a correct token (or one stored in user details – more about that in the list below). I would probably use URL segments here, so that first segment contains the username and second one the token, though. If there's a match, do something (display page content), otherwise throw a Wire404Exception (preferable over displaying a clear message such as "wrong token"; you don't want third parties to know even if they got the username right.) Some additional steps to consider, mainly for security reasons: Instead of calculating the token on the go, you could generate it automatically for every user, and store it in a custom field added to the user template. This way you can also include random data in the original hash, which means that it cannot, under any circumstances, be used to uncover (hashed) passwords or any other type of sensitive data. Note: this would still mean that the token is stored in the database as-is, which would become a problem in case this information ever leaks. Technically the safest thing to do might be to send the private token to the user, and never store it as-is, but rather convert it to a hash using a salt and then store those locally ? Add some sort of brute force protection to the page, i.e. after a few incorrect attempts block the IP for a while. Preferably refresh (recreate) tokens after a set amount of time. This may not be particularly important, but personally I believe it's a good practice in these sorts of situations. Provide a way for users to change (reset) this key, in case there's a chance that someone else has gained access to it. Preferably this new key should also be randomly generated, so that users cannot manually type in a weak key. Use username or some other value in the URL itself, so that keys become much harder to guess (via brute force attack) – but also make sure that third parties can't use these URLs to collect a list of existing usernames ? ... although the security level of course depends on the type of information you're providing via this calendar. If it's not particularly sensitive data, then it won't be such a big deal, but if there's a chance that it may, for an example, contain personal data, then definitely take every possible precaution.
    1 point
  5. The easiest approach might be setting the owner of the whole /site/assets/ directory (and everything in it) as the Apache user (www-data:www-data). If you want to retain easy write access to those directories (without sudo), you can set your own user as the owner, the owning group as www-data, and change the permissions for that directory to 664 instead of 644 – though depending on your setup when www-data creates new files and directories, it will likely overwrite the owner for those files anyway. Usually this isn't a problem, though, since you shouldn't upload files to /site/assets/ manually, and even then it would only be limited to files that www-data is already managing ?
    1 point
  6. On-demand mirroring of remote web server files to your dev environment ???
    1 point
  7. When their family settings are set you can let is put a timestamp in the name. https://processwire.com/docs/modules/guides/process-template/
    1 point
  8. Just in case anyone else is interested, this does the job nicely! $this->addHookBefore('AdminBar::getItems', function($event) { $args = $event->arguments[0]; $args['strings']['browse'] = 'View'; $event->setArgument(0, $args); });
    1 point
  9. Thanks for taking on this module @teppo. A couple of minor styling observations with the Uikit theme... The spacing around the buttons is a little inconsistent. And to my eye the triangle that indicates the active button feels like it's off-centre, because the icon feels like it is separate to the word rather than them both making up a single visual unit. So for the Uikit theme I'd be inclined to centre the active marker on the word alone rather on icon + word. For pages where some buttons are not available... When "Edit" is not available the button text changes (the full stop looks out of place here), but when "New" is not available the button text is gone but the icon remains. Not sure but maybe unavailable buttons should not render at all?
    1 point
  10. It's great to see new life breathed into this module - thanks @teppo. Two things I added to one installation of mine was the ability to edit the user's profile and the other was to restrict them to only be able to edit pages that they have created. Would you consider adding those features? One other thought - I am a bit confused by "browse" vs the old "view" - browse to me suggests browsing through multiple pages, rather than viewing the current one which is what this link does. What do you think?
    1 point
  11. I understand thats it's crucial to save bandwith. That's why we have webP now, finally. But there is one line in PagefileExtra.php that delivers the normal image url instead of the webp version, if the webp filesize is larger. In my case and I think on other sites too this is an unwanted behaviour, as quality and colors are different if you compare a jpg and a webp image. To illustrate this I attached this image, where you can see that the first three products which are being delivered as JPGs because the filesize is smaller are really different looking than the next 3 which are in webp format , especially in the logo area. This is somewhat hard to see here, but on my development site it looks really bad and is a showstopper for me to use webp. What I ask for is an option to skip the filesize check and maybe the option to enter a treshold value when to use the smaller image. I created a github issue "make the fallback optional if pagefile->url is smaller than webp" EDIT: This is already possible if you use following code: //_init.php // output webp version for all $image->url() calls, skip SVG's if($page->template != 'admin') { $wire->addHookAfter('Pageimage::url', function($event) { static $n = 0; if(++$n === 1) { if (strstr($event->object->filename, '.svg') === false){ $event->return = $event->object->webp()->url(false); } } $n--; }); }
    1 point
  12. I found 2-3 forum threads... perhaps you'll find hints what's slowing it down? (setup/config)
    1 point
  13. There's no way to test a migration beyond just using it. That's why I feel the downgrade functionality is so important. It enables you to quickly iterate on things missing. Also keep migrations small and focused on a single concern. Personally I don't even worry about backing up my database just for running a single migration. I'm using CronjobDatabaseBackup, which does a backup every day or so and I've not restored once of of them by now. There's not really to much, where you would destroy something not quickly fixable via the admin backend. For more involved changes, where lot's of pages are affected I also like to split things up in multiple migrations, which I can run manually – checking things after each migration. After a few initial migrations written the potential of bugs will also considerably drop for everything "standard". E.g. creating a field with a FieldMigrations is essentially just setting some properties. The hard stuff is already taken care for. If you make errors there it's a matter of deleting the field and rerunning the migration and everythings fine again.
    1 point
  14. The problem with your approach is, that it only requests the data once and ProcessWire returns all pages instead of those who match the query string. This could be a problem on very dynamic sites, where the content changes often. Here is my solution which solves this: Modify the standard search.php and add if ($config->ajax) { header("Content-type: application/json"); // Set header to JSON echo $matches->toJSON(); // Output the results as JSON via the toJSON function } so the whole file reads <?php namespace ProcessWire; // look for a GET variable named 'q' and sanitize it $q = $sanitizer->text($input->get->q); // did $q have anything in it? if ($q) { // Send our sanitized query 'q' variable to the whitelist where it will be // picked up and echoed in the search box by _main.php file. Now we could just use // another variable initialized in _init.php for this, but it's a best practice // to use this whitelist since it can be read by other modules. That becomes // valuable when it comes to things like pagination. $input->whitelist('q', $q); // Sanitize for placement within a selector string. This is important for any // values that you plan to bundle in a selector string like we are doing here. $q = $sanitizer->selectorValue($q); // Search the title and body fields for our query text. // Limit the results to 50 pages. $selector = "title|body%=$q, limit=50"; // If user has access to admin pages, lets exclude them from the search results. // Note that 2 is the ID of the admin page, so this excludes all results that have // that page as one of the parents/ancestors. This isn't necessary if the user // doesn't have access to view admin pages. So it's not technically necessary to // have this here, but we thought it might be a good way to introduce has_parent. if ($user->isLoggedin()) $selector .= ", has_parent!=2"; // Find pages that match the selector $matches = $pages->find($selector); $cnt = $matches->count; // did we find any matches? if ($cnt) { // yes we did: output a headline indicating how many were found. // note how we handle singular vs. plural for multi-language, with the _n() function $content = "<h2>" . sprintf(_n('Found %d page', 'Found %d pages', $cnt), $cnt) . "</h2>"; // we'll use our renderNav function (in _func.php) to render the navigation $content .= renderNav($matches); } else { // we didn't find any $content = "<h2>" . __('Sorry, no results were found.') . "</h2>"; } if ($config->ajax) { header("Content-type: application/json"); // Set header to JSON echo $matches->toJSON(); // Output the results as JSON via the toJSON function } } else { // no search terms provided $content = "<h2>" . __('Please enter a search term in the search box (upper right corner)') . "</h2>"; } Then call typeahead with the following options: $.typeahead({ input: '#q', order: 'desc', hint: false, minLength: 3, //cache: false, accent: true, display: ['title'], // Search objects by the title-key backdropOnFocus: true, dynamic: true, backdrop: { "opacity": 1, "background-color": "#fff" }, href: "{{url}}", emptyTemplate: "No results for {{query}}", searchOnFocus: true, cancelButton: false, debug: true, source: { //url: actionURL // Ajax request to get JSON from the action url ajax: { method: "GET", url: actionURL, data: { q: '{{query}}' }, } }, callback: { onHideLayout: function (node, query) { $('#searchform').hide(); console.log('hide search'); } } }); The important parts are "dynamic:true" and the "source" configuration so the query string is beeing sent. Now you have a nice AJAX search. EDIT: If you also want to find the query string in other fields than the title make sure you add filter: false to the config of typeahead.
    1 point
×
×
  • Create New...