Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 06/21/2022 in all areas

  1. I created a simple translation module for a project we're currently working on and I thought I would share it in case it's useful for anyone else as it's a request we've come across a few times recently. It's a basic page translation module using Google Translate to replace their now retired embeddable page translation widget. The module outputs a simple, un-styled, dropdown language selector that routes the visitor to a translated version of the current page via translate.google.com. From there you can then navigate the whole site in the your language of choice. There's also a method to output a single language-specific translation URL for any supported language using the language ISO code. Download, usage and supported language list available on my Github here: https://github.com/mrjcgoodwin/MarkupGoogleTranslate Caveat 1: Google seem to be trying to encourage use of their Google Translation API, so the continued working of this module is completely at their mercy - I can imagine they may discourage this usage at some point, but who knows! Caveat 2: I haven't yet deciphered what all the parameters are used for in the constructed Google Translate URL. It's possible there may be some sites/scenarios where the URL doesn't work. Feel free to report if you find any issues.
    1 point
  2. We recently launched DOMiD Labs, a new microsite for our existing client DOMiD. We already built the main site for DOMiD in 2019, as shown in our previous post here and featured in ProcessWire Weekly #296. The new DOMiD Labs site belongs to a project to plan participative museum concepts for the upcoming migration museum in Cologne, Germany. Concept, design and implementation by schwarzdesign - web agency in Cologne, Germany. Featured in ProcessWire Weekly #433 We're using an in-house starter project to bootstrap new ProcessWire projects. This allows us to deliver smaller projects on a low budget while still providing an extensive, modular content system and to spend some time polishing the features our clients care about. Notable features of the site include: A modular content builder utilizing the excellent Repeater Matrix field. A blog area with a paginated news index page. Multi-language support (site available in English and German). Q&A sections using accordion elements. A contact form built with the Form Builder module. Fully configurable navigation and footer components. Custom translation management for interface translations. Learn more: domidlabs.de
    1 point
  3. This week I've been busy developing a site. It's the same one as the last few weeks, which is an established site moving out of WordPress and into ProcessWire. Next week the whole thing is getting uploaded to its final server for collaboration and for client preview. I've been pretty focused on getting that ready and don't have any core updates to report this week, though should next week. One thing about the prior version of this site (and perhaps many WordPress sites) is that there wasn't much structure to the pages used in the site, and hundreds of unrelated pages in the site confusingly live off the root, such as /some-product/ and /some-press-release/ and /some-other-thing/. There's no apparent structure or order to it. And those pages that do have some loose structure in the wp-admin have URLs that don't represent that structure on the front-end. There's very little relation between the structure one sees in the wp-admin and the structure that one sees in the URLs, or in the front-end navigation. They all seem to be completely unrelated. That's one thing that I've tried to fix, so that there is some logic and structure rather than having a bunch of unrelated pages all in the same bucket (is this common in WordPress?) But there's one big caveat. We didn't want to change anything about the actual URLs that are used on the site. This is a site with a long history, a lot of incoming links, and a lot of search traffic. The current URLs have been in place a long time and we didn't want to introduce more redirects into the site (there are already a ton of 301 redirects accumulated over time). So we wanted to make sure the existing URLs in the new ProcessWire-powered site are identical to what they were in the WordPress site. That might seem difficult to do, going from an unstructured WordPress site into a highly structured ProcessWire site... but actually it's very simple. Here's how: Making ProcessWire render pages from WordPress URLs We created a new URL field named "href" and added it to most of the site's templates. For established pages that came in from the old WP site, this "href" field contains the WordPress URL for the page. Depending on the page, it contains values like /some-product/ or /some-press-release/, /some-country/some-town/, etc. In most cases this is different from the actual ProcessWire URL, since the page structure is now much more orderly in the back-end. And for newly added pages, we'll be using the more logical ProcessWire URL. But for all the old WordPress pages, we'll make them render from their original URL. This is certainly preferable from an SEO standpoint but also helps to limit the redirects in the site. In order to make $page->url return the old/original WordPress URL (value in $page->href), a hook was added to the /site/init.php file: /** * Update page paths and URLs to use the 'href' field value on pages that have it * */ $wire->addHookBefore('Page::path', function(HookEvent $event) { $page = $event->object; /** @var Page $page */ $href = $page->get('href'); if(!$href) return; // skip if page has no 'href' value $event->return = $href; $event->replace = true; }); Now we've got $page->url calls returning the URLs we want, but how do we get ProcessWire to accept those URLs for rendering pages? The first thing we'll need to do is enable URL segments for the homepage template. We do this by going to: Setup > Templates > home > URLs > and check the box to enable URL segments. Save. Then we need to edit our /site/templates/home.php to identify when URL segments are present and render the appropriate page, rather than the homepage: $href = $input->urlSegmentStr; if($href) { $href = '/' . trim($href, '/') . '/'; $page = $pages->get("href=$href"); if(!$page->id || !$page->viewable()) wire404(); $wire->wire('page', $page); // set new $page API var include($page->template->filename); // include page's template file } else { // render homepage output } As you can see from the above, when URL segments are present, we find a page that has an "href" field value matching those URL segments ($input->urlSegmentStr). If we don't find one, we stop with a 404. But if we do find one, then we set the $page API variable to it and then include its template file, making that page render rather than the homepage. If there is no $input->urlSegmentStr present then of course we just render the homepage. That's it! By using these little bits of code snippets to replace ProcessWire's URL routing, now all the URLs of the old WordPress site are handled by ProcessWire. Like most things in ProcessWire, there's more than one way to accomplish this… We could have used URL/path hooks, or we could have hooked before Page::render to take over homepage requests with URL segments, before the homepage even got involved. Or perhaps we could have hooked in even earlier, to something in the ProcessPageView module or PagesRequest class. Or we could have used an existing module. Any of these might be equally good (or even better) solutions, but I just went with what seemed like the simplest route, one that I could easily see and adjust. Plus, it'll work in any version of ProcessWire. The actual solution I used is a little more than what's presented here, as it has a few fallbacks for finding pages and scanning redirect lists, plus passes along remaining pagination/URL segments to rendered pages. I'm guessing most don't need that stuff, and it adds a decent chunk of code, so I left that out. But there are a couple of optional additions that I would recommend adding in a lot of cases: Forcing pages to only render from their "href" URL and not their ProcessWire URL (optional) Our existing hooks ensure that any URLs output for pages having "href" values are always based on that "href" value. But what if someone accesses a given page at its ProcessWire path/url? The page would render normally. We might want to prevent that from happening, ensuring that it only ever renders at its defined "href" URL instead. If the page is requested at its ProcessWire URL, then we redirect to its "href" URL. We can do that by adding the following code to our /site/templates/_init.php file: if($page->id > 1) { // ensure that we are rendering from the 'href' URL // rather than native PW url, when href is populated $href = $page->get('href'); $requestUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; if($href && $requestUrl && strpos($requestUrl, $href) === false) { // href value is not present in request URL, so redirect to it $session->redirect($config->urls->root . ltrim($href, '/')); } } Enforcing uniqueness and slashes in "href" values (optional) It's worthwhile to enforce our "href" values being consistent in having both a leading and trailing slash, as well as making sure they are always unique, so no two pages can have the same "href" value. To do that, I added this hook to my /site/ready.php file (/site/init.php would also work): /** * Ensure that any saved 'href' values are unique and have leading/trailing slashes * */ $wire->addHookAfter('Pages::savePageOrFieldReady', function(HookEvent $event) { $page = $event->arguments(0); /** @var Page $page */ $fieldName = $event->arguments(1); /** @var string $fieldName */ if($fieldName === 'href' || in_array('href', $page->getChanges())) { // the href field is being saved $href = $page->get('href'); if(!strlen($href)) return; // make sure value has leading and trailing slashes if(strpos($href, '/') === 0 && substr($href, -1) === '/') { // already has slashes } else { $href = '/' . trim($href, '/') . '/'; $page->set('href', $href); } // make sure that the 'href' value is unique $pages = $event->object; /** @var Pages $pages */ $p = $pages->get("id!=$page->id, href=$href"); if($p->id && !$p->isTrash()) { $page->set('href', ''); $page->error( "Path of '$href' is already in use by page $p->id “{$p->title}” - " . "Please enter a different “href” path and save again" ); } } }); That's all for this week. Thanks for reading, have a great weekend!
    1 point
  4. New search engine on the block .... will their business model work ? yep.com ******************
    1 point
  5. Well, you can just send your POST request in such a way that the Json will be available as $input->post['myData'], that is, as FormData or UrlEncoded: fetch('https://example.com', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' }, body: new URLSearchParams({ 'myData': JSON.stringify(someObject) }) }); or const formData = new FormData(); formData.append('myData', JSON.stringify(someObject)); fetch('https://example.com', { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest' }, body: formData }); If your object is just a simple key-value affair, you may actually want to send it that way and not as Json at all, because you’ll be able to use the sanitizer methods for each value. With the Json you have to parse it and then sanitize the properties, watch out for properties you didn’t want etc.
    1 point
  6. Just keeping this thread up to date in case anyone is searching for how to do this still (and I know I'll forget so it will probably be me), the ProcessPageList module now has a configuration option to let you hide pages from users:
    1 point
  7. Ah, thanks a lot! I was trying to configure an InputfieldTextarea as one would do in the CMS itself and couldn't get it to render. Using the right class worked very well.
    1 point
  8. To make a POST request using the Fetch API, you need to pass the 'method: POST' to the fetch() method as the second parameter: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch | https://reqbin.com/code/javascript/ricgaie0/javascript-fetch-api-example fetch('https://domain.com/api', { method: 'POST' }) .then(resp => resp.json()) .then(json => console.log(json))
    1 point
  9. Thanks for confirming! Looking forward to seeing your 700+(??) variants ?. Probably the heat wave mate ?. Seriously though, glad it's working.
    1 point
  10. Hey and thanks for the interest. I am head of community at CrowdSec and I had never heard about ProcessWire before this, so thanks for pointing me to it. I haven't heard of anyone working on a bouncer (or parsers or scenarios) for ProcessWire. I won't rule out that anyone is, but I doubt it. Could I ask what motivates you to specifically ask for a bouncer? I would say that it probably also would make sense to have a parser that's able to parse PW logs and a scenario able to detect attacks such at bruteforce access to the PW backend (assuming that there is one) for instance. Both the Wordpress and Magento bouncer is really a specialized version of the generic PHP bouncer. Here's an article on how to use it with Drupal but in reality it works with anything PHP. If more people are interested in PW support it would be a great idea to join our Discord and talk about it there. I hope this was to any help. If I can do more please let me know.
    1 point
  11. Important security update! Hi RockGrid users, I'm very sorry for that, but I have to announce a security update. If you are using RockGrid on a public site please upgrade to v0.0.22 (Fieldtype) immediately. It is a simple but important update: https://github.com/BernhardBaumrock/FieldtypeRockGrid/commit/0be2086139c84f775937246ed2985ac4c4a3e9c3; The proplem exists on all RockGrid fields with AJAX turned ON. In this case it was theoretically possible to expose the field data to a user that should not be allowed to see this data (in the worst case even a guest user) if the user knew how to do it and he also knew the name of the rockgrid field. The update now restricts access for AJAX field data to superusers only. You can easily adjust that via simple hooks: // rockgrid access control $wire->addHookAfter("InputfieldRockGrid::access", function(HookEvent $event) { // all grid data is accessible for all logged in users $event->return = $this->user->isLoggedin(); }); Or more granular via the fieldname: // rockgrid access control $wire->addHookAfter("InputfieldRockGrid::access", function(HookEvent $event) { $field = $event->arguments(0); $user = $this->user; $access = $event->return; switch($field) { case 'field1': case 'field2': case 'field3': $access = $user->isLoggedin(); break; case 'field4': $access = ($user->name == 'foo'); break; } $event->return = $access; }); Field 1-3 is allowed for logged in users, field4 only for user foo and all other fields only for superusers (default rule). I'm not totally happy any more with several aspects of RockFinder and RockGrid, but it is the best option I have so far (until I can build something totally new, maybe with tabulator if tests work well). Special thx to @Zeka for bringing this issue to my attention by coincidence in the other topic!
    1 point
×
×
  • Create New...