Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 02/16/2021 in all areas

  1. Now that you mention it, the first thing that strikes me is how often I have to build endpoints like this over and over again on every project. ?? I think that would be a really useful feature request, to have a fixed endpoint, which then each module can extend and have access to it.
    2 points
  2. Dude, at what point did I tell you to try that ? If you want to use that module, you need to familiarize yourself with it. Unfortunately there doesn’t seem to be any documentation apart from what’s in the code itself. What it does is add a method called render() to the PageArray class. Internally that calls MarkupPageArray::renderPageArray(), but you still need to write $items->render(). Now you need to figure out what arguments to pass. The information is in the code I linked. It takes an associative array of options, none of which are an actual template file like what you want to do. You could do something like this if you really wanted to: $items->render(array( 'listMarkup' => '<ul>{out}</ul>', 'itemMarkup' => "<li> <h3>{title}</h3> <p><strong>price: </strong><span>{price}</span> <p><strong>category: </strong><span>{category}</span> <p>{body}</p> </li>" )); But really, just use the foreach. Sorry for posting more confusing alternatives than anything. Do the foreach, it’s exactly what you want. You can write it in a single line if it feels cleaner. I haven’t tested any of this, I’m just writing it into the comment box.
    1 point
  3. In somelayout.php the current Page is in the $page variable! It doesn’t know $item. Otherwise your loop should work. PageArray doesn’t have a render method, although I guess you could do $items->each(fn($item) => echo $item->render('somelayout.php')); (or something like that)
    1 point
  4. Would you mind adding this to the Github requests repo? I'd do it, but I feel like I've added so many requests and issue lately that Ryan is starting to tune me out ?
    1 point
  5. Yeah, I understand the reasons - it's a shame PW doesn't have a dedicated endpoint that is automatically available on all installs so we don't have to deal with hacking into 404. I have wished for something like this many times - I wonder if maybe it should be a feature request?
    1 point
  6. Yes, I understand. Unfortunately, this case cannot be mapped with the module, because the whole core concept is based on triggering a 404 via a non-existent endpoint and hooking in before it. I wanted to keep it simple and not have to install an additional page as API endpoint and a template for it. ?
    1 point
  7. @David Karich - defining URL segments does seem to fix all the issues. However, I am concerned about setups where the definition would allow matching "phcv1" - mine are specific enough at the moment, but I can see it being an issue, especially if you have a segment for catching incoming affiliate links, or something similar with one segment that allows any alphanumeric characters.
    1 point
  8. Yes, this is the problem described. Just tested it. Forget what I said before. This error occurs only when there are missing segment definitions with segments enabled. Edit 1: Just validated it again too, there is no other way. You need to define the URL segments or leave placeholders via regex so that an endpoint can be created and there is a possibility that a 404 will be triggered. And without a segment definition a 404 will never be triggered and so the script can't hook in at that point. Edit 2: Consequently, the request is not going to the module, but simply to your page, which itself is the response in your console in debug mode. But the tracking endpoint can also not be placed uniformly on the root, because in cookie mode with differentiated URL segments the cookie must be stored only on this path. I will think about whether there should be an alternative way without AJAX. But I can't implement this adhoc, because I don't have the time for it and for this project no customer releases budgets anymore, because these use cases for which it was needed, work like this. @adrian Please define the URL segments in your project and test it, it should work with that. ?
    1 point
  9. I think you have the PW debug mode on, right? The response is not returned when debug mode is off. Also, all non-AJAX based requests are not processed further. https://github.com/FlipZoomMedia/PageHitCounter/blob/master/PageHitCounter.module#L643 Or have I misunderstood something?
    1 point
  10. here is one from ryan: here is another (that I don't know) and more can be find using the g**gle site search.
    1 point
  11. Hi @adrian, unfortunately I can't reproduce the problem on any installation where I just tested it. The module does not handle the uninstall process manually either, it uses PW's native methods: https://github.com/FlipZoomMedia/PageHitCounter/blob/master/PageHitCounter.module#L1130 – There I'm confused unfortunately, why when uninstalling the field your MySQL table is not removed. Maybe local development environment with wrong rights? ? Surely this would also work, but this makes it in the end, I think, unnecessarily inflated in the code. The current method does not block the rendering process because rights, templates, filters, cookies, etc. have to be checked first and then an SQL query has to be waited for before it continues (even if it is only milliseconds here). It is therefore asynchronous and does not block the frontend. It clears the way for self-created AJAX requests for tracking and it works as it is implemented, for all methods. Whether ProCache is in use or not. ? The module should never become a tracking or statistics module in its concept. There are simply enough better tools that you can use for that. It has always been and should remain so, a simple way to quickly sort by interests or get an overview without big bells and whistles. Everything that is based on template, you can track with it but also. See the Custom API tracking methods. So if your downloads have a template in any form, you can also use it to map a download counter. For example, I have already mapped this with login counters. (https://github.com/FlipZoomMedia/PageHitCounter#example-tracking-a-page-hit-via-api-and-jquery) For everything else there is Analytics or Matomo, or the many other tools. But ask @bernhard, I don't want to anticipate anything, but he builds something great on the basis of the PageHitCounter. ?
    1 point
  12. If you’re up for it you can just create your own login form and send the input to $session->login(). That may be sufficient if you really manage everything yourself, but if you need users to do “Forgot Password”, change their passwords and all that annoying stuff, the module will probably be worth it.
    1 point
  13. Not necessarily. The username of your email account is independent from the sender address – this is why, for example, you can have one email account with multiple associated email addresses. Though some providers don't make that distinction clear, and nowadays your username is usually the primary email address, so most people (in my experience) are not aware that those are two different things. WireMailSmtp needs the username of the account to log in, and often this is the same as the sender address, but it doesn't have to be. This is why you can specify the username and sender address separately. WireMailSmtp doesn't care about the domain the sender address belongs to, any restrictions regarding that are done by the mail provider. What matters for verification and spam prevention is the domain you're sending from. If you're sending from @your-domain.com and you've properly set up the SPF and DKIM records for your mail server, your mail server can send emails from every address @your-domain.com without problems. Of course, any mail provider / server tool can add any restrictions for sender addresses they want on top of that. For example, if you send your Email through Gmail, it probably won't let you use a sender address that doesn't belong to your account. So it comes down to what email provider you're using.
    1 point
  14. In theory, no, you can use any field you want for the From field in the e-mail. In practice however, many email providers will block this, as it's essentially spoofing. And even if your provider doesn't reject emails like this entirely, they will probably go directly to the spam folder, as your server probably is not authorised to send mail from this domain (using SPF, DKIM or similar methods). The mails might even be rejected entirely, depending on DMARC records. And for good reason – you wouldn't want just anybody to be able to send spam that appears to have been sent from your address, right? You shouldn't send unauthenticated emails, and by the way you also shouldn't send emails without SSL – but that's a separate issue. Yes, it is. That's what the reply-to field in an email is for. This way, you can have a sender address (From field) that's clearly coming from your domain (something like no-reply@your-domain.com) and a different recipient for answers, which is the correct way to approach this. That said, I have encountered one hosting provider that blocks emails where either the from OR the reply-to email don't belong to a domain that is registered with that provider. In this case, you'd have to find a workaround, like sending the email to both recipients and instructing them to hit reply all. Or integrate messaging into your application instead of using email. Alternatively, you might use mailto links with pre-filled recipient, subject line and body and instruct your users to send their own mail. Which might be cleaner in terms of email security / authentication, though it depends on your application.
    1 point
  15. I've created an issue on this in the processwire-issues repo: https://github.com/processwire/processwire-issues/issues/1330
    1 point
  16. This is the crux of the issue. If the user shouldn't be able to edit a field then you don't want it included in the ProcessProfile form, but as you say this causes issues with inputfield dependencies. My suggestion is: 1. Only include editable fields in ProcessProfile. 2. Remove the showIf condition when the dependent fields appear in ProcessProfile. 3. Implement the same showIf logic to determine which fields are editable in ProcessProfile. Example... In this case I have fields text_1, text_2 and text_3 in the user template. The text_2 and text_3 fields have the showIf condition "text_1=foo". But I don't want the user to be able to edit text_1 in ProcessProfile so I disable that field in the ProcessProfile module settings: In /site/ready.php: $wire->addHookBefore('ProcessProfile::execute', function(HookEvent $event) { /** @var ProcessProfile $pp */ $pp = $event->object; // The fields that have a showIf dependency on a field not editable in ProcessProfile $dependent_fields = ['text_2', 'text_3']; // If dependency condition not met, remove dependent fields from the ProcessProfile editable fields if($event->wire()->user->text_1 !== 'foo') { $pp->profileFields = array_diff($pp->profileFields, $dependent_fields); } // Remove showIf condition from dependent fields $event->wire()->addHookAfter('Field::getInputfield', function(HookEvent $event) use ($dependent_fields) { $inputfield = $event->return; if(!in_array($inputfield->name, $dependent_fields)) return; $inputfield->showIf = ''; }); });
    1 point
  17. I just released version 1.1.3 which resolves three issues that were reported recently: Fixes an issue with the constructor signature of the modules AppApiException class (by @David Lumm, thanks for PR ?) Fixes an issue with the error-handler, which made it mistakenly catch errors that should have been ignored via @ operator (Thanks to @eelkenet) Switched from `wire('input')->url` to `$_SERVER['REQUEST_URI']` for reading the base-url, because ProcessWire's internal function transferred everything to lowercase. (Thanks to Github-user @pauldro) Thank you all for your contributions!
    1 point
  18. Hi @Sebi, I ran into a bug: Currently the Router::handleError() function incorrectly reports HTTP 500 errors that result from methods that should have remained silent, because they are called with the error control operator '@'. As the PHP documentation on error control operators puts it: I bumped into this while working on a project with some semi-broken images, where the APP API module kept throwing 500's from PW's ImageInspector class. Exif issues can be rather difficult to handle sometimes.. The solution is simple: just add a check error_reporting() before the handleError method, for instance public static function handleError($errNo, $errStr, $errFile, $errLine) { if (error_reporting()) { $return = new \StdClass(); $return->error = 'Internal Server Error'; $return->devmessage = [ 'message' => $errStr, 'location' => $errFile, 'line' => $errLine ]; self::displayOrLogError($return, 500); } }
    1 point
  19. I'll just leave this here: How to set up Twig as a flexible view layer for ProcessWire and/or Create flexible content modules using Repeater Matrix fields The feature you're looking for is template inheritance – the ability to have a base template which is extended by child templates. The child templates can then override any block they want to. If you go down the path of wireRenderFile or MarkupRegions you'll always notice you're fundamentally lacking the ability to overwrite blocks in a parent template. With pure PHP templates, you'll always end up with a system that either needs to import a bunch of partials in every new template, just for the ability to leave out or change some of them for one particular template. Or your base template will need to be aware of every possible permutation and arrangement of partials and mixins in all your templates, resulting in messy and unmaintainable code which grows linearly with every template you add. Using a template system with template inheritance solves that for you and makes your template system infinitely scalable (besides other benefits like autoescaping and better readability).
    1 point
  20. Without needing to buy a Pro module (although they are excellent!), there is indeed a ProcessWire way for this. You can use $files->render()/wireRenderFile() to achieve what you want: https://processwire.com/api/ref/wire-file-tools/render/ https://processwire.com/api/ref/functions/wire-render-file/ The advantage of using this over your own functions is that it will automatically keep access to all of PW's API variables (no need to pass them in). Here is a simple example based on your use-case description: /** * In your generic template file. * Note: it assumes there is a directory under 'templates' called 'layouts' (it could be called anything). * Just create your layouts in the 'layouts' dir and name them the same as the '$item->template' names you are using. */ // Get the content of the specified layout into a variable. // This example looks for '/site/templates/layouts/name-of-template.php' (the .php extension is assumed) $pageContent = $file->render('layouts/' . $item->template); // Just echo it out wherever you need it. echo $pageContent; Read the docs on it, there is more you can do with this method/function, including passing custom variables, and some other options to make it more flexible. There is also a $files->include() method which is the same except it directly echos out the content instead of returning it to a variable.
    1 point
  21. Sure. I have that installed as well. But very often, I need to do stuff that's not possible with that module, or simply easier to do writing a few lines of code myself.
    1 point
  22. The module source is below. Example usage: a checkbox on a contact form (using Form Builder) for the user to subscribe. It's used on https://ricardo-vargas.com/contact/ EXAMPLE A method on _hooks.php. If you don't use Form Builder, use this code on your form page. $forms->addHookBefore('FormBuilderProcessor::emailForm', function($event) { $processor = $event->object; if ($processor->formName == 'contact-form') { $formData = $event->arguments(1); $contact_name = $event->sanitizer->text($formData['contact_name']); $contact_name = substr($contact_name, 0, 30); // limit length further $contact_name = $event->sanitizer->emailHeader($contact_name); $contact_email = $event->sanitizer->text($formData['contact_email']); $contact_email = $event->sanitizer->emailHeader($contact_email); $processor->emailFrom = $contact_email; //reply to $processor->emailSubject = 'Message from '.$contact_name; $form = $event->object->getInputfieldsForm(); $subscribe = $form->get('receive_updates'); $list_id = $form->get('sendy_list_id')->attr('value'); // check to see if they subscribed if ($subscribe->attr('checked')) { $success_url = '/contact'; // $fail_url = '/contact?error=1'; $ProcessSendyAPI = wire('modules')->getModule('ProcessSendyAPI'); $ProcessSendyAPI->subscribeInSendy($contact_name, $contact_email, $list_id, $success_url); } } }); MODULE https://gist.github.com/sjardim/2d834ebb0bd66d4da1ac16072f4075cd <?php namespace ProcessWire; class ProcessSendyAPI extends WireData implements Module, ConfigurableModule { public static function getModuleInfo() { return array( 'title' => __('Process Sendy API'), 'summary' => __('Handle API calls to a Sendy installation'), 'author' => 'Sérgio Jardim', 'version' => '001', 'singular' => true, 'autoload' => false, 'icon' => 'envelope' ); } /** * Data as used by the get/set functions * */ protected $data = array(); /** * Default configuration for module * */ static public function getDefaultData() { return array( "sendy_api_key" => '', "sendy_installation_url" => 'http://www.example.com/sendy' ); } /** * Populate the default config data * */ public function __construct() { foreach(self::getDefaultData() as $key => $value) { $this->$key = $value; } } public static function getModuleConfigInputfields(array $data) { $data = array_merge(self::getDefaultData(), $data); $wrapper = new InputfieldWrapper(); $f = wire('modules')->get('InputfieldText'); $f->attr('name', 'sendy_api_key'); $f->label = __('Sendy API Key', __FILE__); $f->description = __('Further instructions at https://sendy.co/api', __FILE__); $f->notes = __('Get your key at http://your_sendy_installation/settings.', __FILE__); $f->value = $data['sendy_api_key']; $wrapper->add($f); $f = wire('modules')->get('InputfieldURL'); $f->attr('name', 'sendy_installation_url'); $f->label = __('Sendy instalation URL', __FILE__); $f->description = __('Your Sendy installation URL without a trailing slash', __FILE__); $f->notes = 'http://www.example.com/sendy'; $f->value = $data['sendy_installation_url']; $wrapper->add($f); return $wrapper; } /** * [subscribeUserOrGuest description] * @param [type] $name [description] * @param [type] $email [description] * @param [type] $list_id [description] * @param [type] $success_url [description] * @param [type] $fail_url [description] * @return [type] [description] */ public function subscribeInSendy($name, $email, $list_id, $success_url = null, $fail_url = null) { $api_key = $this->data['sendy_api_key']; $sendy_url = $this->data['sendy_installation_url']; $postdata = http_build_query( array( 'name' => $name, 'email' => $email, 'list' => $list_id, 'boolean' => 'true' //set this to "true" so that you'll get a plain text response ) ); $opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata)); $context = stream_context_create($opts); $result = file_get_contents($sendy_url.'/subscribe', false, $context); //check result and redirect if($result) { $this->wire('log')->save("newsletter", 'A new user subscribed to the site mailing list: '.$email); if($success_url) { header("Location: $success_url"); } } else { $this->wire('log')->save("error", 'Error occurred on subscribing '.$email); if($fail_url) { header("Location: $fail_url"); } } } }
    1 point
×
×
  • Create New...