Leaderboard
Popular Content
Showing content with the highest reputation on 07/15/2021 in all areas
-
I am back again with another crazy module that might help someone. This time I am using the native Tfa class to add FIDO/U2F support. this includes Yubikeys ? Sadly I cant seem to find a way to do multiple keys at once. and it seems you can only have one Tfa method at a time so not ideal but it was a fun challenge to code and maybe someone will a use for it Github: https://github.com/adamxp12/Processwire-TfaU2F ProcessWire Modules: https://modules.processwire.com/modules/tfa-u2-f/ The code is not the neatest and has limited comments but if you understand the Tfa class it should be quite easy to break apart. And here is a demo of signing in using the Yubikey as the 2nd factor1 point
-
We're very keen on producing accessible websites (hey, I'm sure we all are) and we make sure that any website designs we create hit accessibilty targets. We do a lot of work with public sector bodies who have legal requirements to meet. But it looks to me as if the default admin interface doesn't hit those targets. Running the WAVE accessibility tool on a default admin page pulls back a bunch of contrast errors and about 10 other errors. We can fix the contrast errors easily enough (especially now we have the Less module) and I suspect most of the other errors should be relatively east to fix (they mostly seem to be missing labels and broken aria tags) but one thing that looks more problematic is being able to navigate using the keyboard. At the moment you don't seem to be able to use the dropdown menu or page lister without using the mouse. Keyboard navigation is one of the legal requirements for lots of our clients here in the UK. So before I dive in has anyone done any work on fixing accessibility in an admin theme? Or is this a fundamental issue with UiKit? EDIT: seems you can tab onto the page lister in Chrome even if you can't in Firefox, which improves things a lot but I still can't seem to use the dropdown menus... EDIT 2: So in Chrome you can tab to the top nav menu items but there's no visible focus. And whilst you can't view the dropdowns (at least I can't) then you can navigate to top level page.1 point
-
Here you go! You need to decide how big each batch will be and set the $startPage and $endPage values each time you run the script. For example, if you have 1230 pages and decide to run the script three times you could use 0 and 499; 500 and 999; 1000 and 1300. Note that you should start at 0 (because the indexing of the page array starts at 0). And it's OK if the last number is larger than the total number of pages. Note also that I haven't tested the code, so let me know if it doesn't work! <?php // If you put the script in /site/ this is OK (otherwise you may need to amend) include("../index.php"); // Change these two values for each batch $startPage = 0; $endPage = 499; // Change the selector to match your pages $selectedRecords = $wire->pages->find("template=my-template"); echo "Pages with images: " . count($selectedRecords) . "<br/>"; $pageCounter = 0; $recordsProcessed = 0; foreach($selectedRecords as $thisRecord) { $pageCounter += 1; if (($pageCounter >= $startPage) && ($pageCounter <= $endPage)) { echo $thisRecord->title . "<br/>"; $recordsProcessed += 1; if(count($thisRecord->article_images)) { $thisRecord->of(false); foreach($thisRecord->article_images as $image) { $description = $image->description; $credit = $image->credit; $image->photo_caption = $description; $image->photo_credit = $credit; $thisRecord->save('article_images'); } $thisRecord->save(); } } } echo "<p>Records processed: {$recordsProcessed}</p>"; ?>1 point
-
On another sidenote, in this part of your code if ($input->get){ ... }else { ... } $input->get will always return true, even if you do not have any GET parameters in your URL because $input->get returns an WireInputData object. You should use if(count($input->get)) // returns 0 if there are no URL params instead.1 point
-
1 point
-
I prefer your approach @netcarver It appears to be working quite well. Thank you for that option.1 point
-
Here is my Caddy 2 config for a PW site: mysite.fi, www.mysite.fi { encode gzip tls my@email.com root * /var/www/mysite/pw file_server php_fastcgi unix//var/run/php-fpm/php-fpm.sock { health_timeout 10000s } @deny_hidden path_regexp /\. @deny_root path_regexp /(CONTRIBUTING|COPYRIGHT|LICENSE|README|htaccess)\.txt @deny_assets path_regexp ^/site(-[^/]+)?/assets/(.*\.php|backups|cache|config|install|logs|sessions) @deny_install path_regexp ^/site(-[^/]+)?/install @deny_config path_regexp ^/(site(-[^/]+)?|wire)/(config(-dev)?|index\.config)\.php @deny_modules path_regexp ^/((site(-[^/]+)?|wire)/modules|wire/core)/.*\.(inc|module|php|tpl) @deny_templates path_regexp ^/(site(-[^/]+)?|wire)/templates(-admin)?/.*\.(inc|html?|php|tpl) rewrite @deny_hidden /denyaccess rewrite @deny_root /denyaccess rewrite @deny_assets /denyaccess rewrite @deny_install /denyaccess rewrite @deny_config /denyaccess rewrite @deny_modules /denyaccess rewrite @deny_templates /denyaccess # global rule try_files {path} {path}/ /index.php?it={path}&{query} log { format single_field common_log output file /var/log/www/access.log { roll_size 50MiB roll_keep 5 roll_keep_for 168h } } }1 point
-
I'd definitely try @netcarver's suggestion first. And if that doesn't work, you could try putting this after saving the record, though I'm not sure if it will make a difference: $pages->uncacheAll(); Then if you still have the problem, for a one-off task you could split the processing into batches. Doing something like the following is highly inefficient, but simple and will definitely work – and is probably more efficient than spending a lot of time trying to find a better fix! $startPage = 0; // Manually change this for each batch $endPage = 1000; // And this too $pageCounter = 0; foreach($pageToProcess as $thisPage) { $pageCounter += 1; if (($pageCounter >= $startPage) && ($pageCounter <= $endPage)) { // Process $thisPage here } }1 point
-
The problem here is that it depends a lot on your setup, i.e. which output strategy you're using and how your site is set up etc. ? If you're using simple direct output (templates/template_name.php directly renders output) then you could do something as simple as this: <?php namespace ProcessWire; // finding results goes here if ($config->ajax) { // render results without page "frames", i.e. just the list of cards // ... and when done, halt the rendering process: $this->halt(); } // normal page output Now you just need to trigger an AJAX request to the same page, read the output, and then replace the part of the page content that you wish to be "dynamically filtered" with new content. Note that for $config->ajax to work, your AJAX request needs to include the "X-Requested-With: XMLHttpRequest" header; jQuery adds this automatically, but if you're using raw XMLHttpRequest, Fetch API, or any other approach to trigger the request then you'll likely have to add that header yourself. More examples for AJAX loading content (including alternative approach, where instead of content you return JSON and then render output in JavaScript) can be found from this thread: Loosely related, but a couple of issues I spotted in your sample code: You're passing $chan and $cont values to the selector string unfiltered. This is not a good idea: visitors could pass in characters that break the query, or even rewrite the query. Always run user-provided values through Sanitizer methods ($sanitizer->selectorValue()) is a good default, but if you're expecting integers then use $sanitizer->int(), etc. Since you're first finding all results and then limiting them, you will run into performance issues if there's a lot of data. As a general rule of thumb always include a limit in your initial selector — this way the limit is applied in the database, which is much more efficient.1 point
-
Maybe you are hitting the max execution time for your script. Check the docs for set_time_limit(), they may help.1 point
-
Thank you Teppo for that detailed answer. Really appriciate it. My first take was similiar to Wireframe. Adding a Template as alternate Template file and replace the render accordingly. But it didnt felt quite right, taking the tools Symfony provides into consideration. I now let Symprowire act as a drop-in solution to replace ProcessWire rendering completly. What this basically means is, ProcessWire will no longer be in charge about anything URL or rendering related. As of now Symprowire will intercept the Request and manage routing decoupled from ProcessWire. So ProcessWire will step back and act as a Data/Service Provider for Symprowire. What I actually did here is separating into more or less 3 layers. ProcessWire as Data and Server Provider Symprowire as Businesslogic Backend MVC style powered by a Symfony Architecture a separated Frontendlayer served by Twig Templates ProcessWire Admin will be used as Data Editor / Content Management System and Symprowire will consume this data and do stuff with it before handing over to Twig.this This would describe it best I guess. I actually use Wireframe as Output Framework in the Project im working on ? I am still not sure if this should be a possibility or an option in Symprowire. Its tempting to let the Developer decide, but on the other hand I mainly create Symprowire to give a somewhat strict structure and to have Phpunit tests in the not so far future. Which would be hard to integrate if just parts could be tested. Decisions decision decision... ? Another reason I am into this is the clear and concise way Symfony handles the Request/Response, it just makes so much sense for me to combine this both worlds. Take the very very strong parts CMS/CMF wise from ProcessWire and combine it with Symfony. I dunno ? just feels to be like this Dont worry, I knew you would give great insights the moment I tagged you ? Have to dig into TemplateEngineFacotry code now ?1 point
-
Hmm, are you sure it's working as you need it to? I would have thought you'd do an intersection and then just check if the intersection is empty or not - which makes me think I've not understood what you are trying to do here. I'm imagining something like this: you have some set of titles like [0 => "Alpha", 1 => "Beta", 2 => "Gamma"] from the explode and you get the following session data ["Delta" => 'whatever'] To see if any of the values from the titles split were in the session keys I'd do something like this... /** * $titles is the array of exploded titles. NB The title strings must appear as values in the array * $session_vars is the array of session variable names => session variable values **/ $intersection = array_intersect($titles, array_keys($session_vars)); if (empty($intersection)) { // Non of the $title values appeared as keys in the $session_vars. } else { // At least one of the $title values appeared as keys in the $session_vars. } If you're happy with the result though, all's good.1 point
-
1 point
-
I can't say that I have a strong opinion here either. Also not sure if I grasp the whole context — when you say "routing" and mention URL segments, does that mean that you create routes automatically based on page structure (I assume so but...) or that there's a separate routing setup for front-end and page structure is only reflected in the data? Or do you mean something different with this? ? This may or may not be related, but one thing to consider is whether you want Symprowire to be "all in", or rather something that can be used only for some parts of the site. Couple of examples from other MVC(ish) solutions: Template Engine Factory hooks before Page::render and replaces the response, but also provides hookable method (TemplateEngineFactory::shouldRenderPage) for preventing it from rendering the page, in which case the site will fall back to the regular rendering flow (whatever that happens to be). Wireframe takes an entirely different approach: instead of a hook ("enabled by default") you need to point templates that you want to render via it to the front controller file via Alternate Template Filename setting (more details in the docs). Essentially it's disabled by default. Wireframe is my pet project and something we've used for our production sites for a while now, so that's what I'm mostly familiar with. I intentionally decided not to use hooks, since I felt it was best to let the developer decide if they want to use Wireframe for everything, just a small part of the site, or something in between. In fact it's possible to skip the MVC structure entirely, and just use Wireframe for its partials and/or components ?♂️ Template Engine Factory may be a bit closer to Symprowire feature wise, although Symprowire clearly has a much larger scope (and is more opinionated). So not sure if any of what I've said here applies as-is ?1 point
-
You have a couple of options: You can create the required fields (and templates, if any) programmatically in the install() method of your module (see the documentation). Creating fields through the API is pretty straightforward, though you might have to dig a bit to find the properties you need if you want to customize the field's settings. In this case, you should probably also handle removing those fields in the uninstall() method so your module can be uninstalled cleanly (make sure to warn the user that uninstalling the module will remove all of it's data in this case!). The benefit of creating regular fields in your module is that your module's data can be managed through ProcessWire's regular interface, and you don't have to provide your own custom interface for simple CRUD operations. An approach that might be better suited if your module is targeted at developers is to make the fields to be used for storing data configurable. You can build module configuration options to let the developer select which templates and fields are used to store the data your module uses. Though this doesn't work for every use case. Finally, you can bypass regular fields entirely and store your module's data seperately. The advantage of that is that it's easy and quick. The downside is that you will have to provide your own interface for displaying and editing your modules data. Of course, that doesn't apply to every module – for example, you wouldn't need an editor interface to edit a user's cart. But if you store completed transactions, your module users will probably expect an interface to list (export, edit, delete, ...) all transactions, at which point you would have to build your own interface for that. Where you store the data is up to you: In the session or cookies (only for ephemeral data, like a cart). In a page's meta() data. I do that in some of my modules, see my post here. You can also use a custom database table for more elaborate storage capabilities. Again, you would use the install() and uninstall() methods of your module to create and (optionally) tear down your custom tables. See this post for some examples. Personally, I prefer modules that adopt best practices of the system they're build for – in the case of ProcessWire, I'd say it's best practice to create regular fields and templates instead of custom tables. But the ultimate answer is – as always – "it depends".1 point
-
I've been using this: 7g firewall with my Processwire sites: https://perishablepress.com/7g-firewall/ Seems to be working effectively.1 point
-
This is the way. Performance is relative. Using a hook to check if a duplicate record exists will always be fast, or at the most have linear complexity. How many users do you expect to add each day? How many users / people entries in total do you have? If it's 10 million, then you'll have to start thinking about the performance of a uniqueness check, but if it's significantly less ... Besides performance, what other benefits do you hope to gain by using a unique index in SQL as opposed to a custom check on the interface-level (i.e. a ProcessWire hook)? The only thing I can think of is that uniqueness is guaranteed at database level, but is that going to matter to you? If you use the right hook, you can prevent duplicate entries from both the CMS interface and ProcessWire's API, so unless someone is going to manually insert records to your database through the command line, the result is identical. By the way, the unique setting for pages guarantees a globally unique page name, not uniqueness of an individual field. Just set the name to include the first name, last name and address (you can do that through the template settings or use a hook if you need more control) and use a hook to set new pages to unique. This will guarantee uniqueness for that combination of fields. Granted, it's only guaranteed on API level, not database level, but again, this might be absolutely enough for your use-case.1 point
-
Those numbers seem pretty normal. Just for comparison: The doc (HTML) part of a fairly complex site I recently finished takes ~600-900ms when I'm bypassing ProCache. This is from browser, though, so could be a bit different from what you're measuring (not sure how exactly you got these numbers). With ProCache I'm getting consistent < 100ms. ProCache serves content directly from disk (via Apache), bypassing PHP and database, so it's naturally quite a bit faster. Took a cursory glance at a couple of (also relatively complex) WordPress site that I know for a fact are well built and hosted on pretty powerful hardware, and load times for these were somewhere between ~1.5-3 seconds uncached, 200-400ms cached (static cache using nginx, I believe). In my opinion 1-3 seconds would still be "pretty good" for just about any ProcessWire or WordPress site without proper caching. Anything below 4-5 seconds is in the "pretty normal" range, while 5-10 seconds is just plain wrong (but sadly not that rare). 5+ seconds is usually a sign of really bad hosting, or really bad implementation ? Might be worth noting that, in my experience at least, PHP is rarely the real bottleneck: if the server returns the markup in a few hundred milliseconds but then there's blocking JavaScript, CSS, or perhaps a large image that takes hundreds of milliseconds to seconds at worst to finish loading and/or executing, it would be better to focus on that. Just saying; developers (including yours truly) have a tendency to focus way too much on shaving milliseconds off one end, even if at the other end it might be possible to shave off seconds ? Template cache loads the page from the disk and doesn't execute any of your markup generating code, but it still has to go through ProcessWire, so there's definitely some overhead there compared to ProCache. How beneficial template cache is (in comparison to non-cached site) depends a lot on how complex the site is and how well it's already optimized. Kind of covered this already, but to reiterate: it would definitely make a difference. ProCache is usually low maintenance, but this depends a bit on how your content is generated — such as whether it's all from stored with/in ProcessWire, or if you have parts that are loaded (especially with PHP) from other sources. Typically ProCache gets flushed based on predefined rules when pages are saved, so if your content isn't stored on pages, that could be a potential issue. In which case you may even need to programmatically flush it (via cron or some other method). You can configure the preferred lifespan, so technically you can make ProCache stick to cached data almost indefinitely, and thus ProcessWire/ProCache will very rarely need to regenerate it. Though, again, in my opinion this is something that folks tend to pay too much attention to: if your typical page render (non-cached) takes 1-3 seconds at most and your cache hit ratio is 99+%, cache warming has so little actual effect that it's (in my opinion) mostly just wasted time and effort ?1 point
-
Right! Multiple Key support is now included. you can put about 19 in before you run out of space (20480 characters, each key uses about 1040) if someone has 19 keys I will be very surprised. I have bumped the version to 1.0.1 as a result. I ain't a big versioning guy but this is a minor change from the users perspective. you can just click the add button more than once now. Just be sure to only click the save button once you have added all yours keys. I have tried it with the 3x keys I have and it works fine. More than 3? not sure cant test that yet. if you click save before you add all your keys then you will only get the ones you added and have to disable/re-enable Tfa to add them all again. This is a limitation of the Tfa class sadly.1 point