Jump to content

PWaddict

Members
  • Posts

    998
  • Joined

  • Last visited

  • Days Won

    3

Everything posted by PWaddict

  1. With the 1.4.0 version, after I click the image icon on TinyMCE to upload the image and insert it to the body field and finally save the page I'm getting this Error: Class "DOMDocument" not found in C:\laragon\www\mysite\site\modules\ProcessCustomUploadNames\ProcessCustomUploadNames.module.php:308 The 2.0 version doesn't have any issues when I'm doing the above method for TinyMCE. On another page where I have 1 image field (single image), on every 2nd save the image is renamed with -1. So, first the image is saved "mysite-123" as I want it and then if I save the page again, the image renamed to "mysite-123-1", if I save the page again the image will get back to what I want "mysite-123" and if I hit save again it will become "mysite-123-1" and so on... Also, if I try to upload new image or delete the current one and hit save, the page gets unpublished. Note: These testings didn't happened on a clean PW installation. For now, I'm gonna stay with my forked version as at least for me there are 0 issues. I will get back to you probably next week with more testings but this time on a clean installation.
  2. Hi @adrian When uploading and inserting an image into a field (e.g., a TinyMCE "body" field) with this module active, any UTF-8 characters (like Greek letters) in other Textarea fields on the same page (e.g., a plain text "seo_description" field) are unexpectedly converted into HTML entities (e.g., "α" becomes "&alpha;" ) and saved to the database. I asked Gemini to provide a solution. Steps to Reproduce: Create a page with a TinyMCE field (body) and a standard Textarea field (seo_description). Enter UTF-8 characters (e.g., Greek text) into the "seo_description" field and save. Upload and insert an image into the "body" field. Save the page. Check the "seo_description" field or the database; the UTF-8 text has been converted to HTML entities. Root Cause Analysis: The issue stems from the "replaceRteLinks" method, which is triggered to update image URLs after a rename. Scope Logic: The method fetches all fields of type FieldtypeTextarea and FieldtypeTextareaLanguage and processes them using DOMDocument, regardless of whether the field actually contains the image URL. Encoding Handling: DOMDocument::saveHTML() natively converts extended characters into HTML entities. Because it processes unrelated fields, it permanently alters their raw text in the database. Proposed Solution: Updating the "replaceRteLinks" method to strictly check if the field contains the target URL before processing it, and utilizing ProcessWire's native sanitizer to restore entities converted by DOMDocument. Here is the patched method: private function replaceRteLinks($newFilename, $oldFilename) { $textareaFields = $this->wire('fields')->find("type=FieldtypeTextarea|FieldtypeTextareaLanguage"); $fieldsStr = $textareaFields->implode('|', 'name'); $oldRelativeUrl = str_replace($this->wire('config')->paths->root, '', $oldFilename); $oldRelativeUrlSansExt = str_replace(pathinfo($oldFilename, PATHINFO_EXTENSION), '', $oldRelativeUrl); foreach($this->wire('pages')->find("$fieldsStr%=$oldRelativeUrlSansExt, include=all") as $p) { foreach($textareaFields as $taf) { // FIX 1: Only parse the field if it actually contains the image URL. if($p->$taf != '' && strpos((string)$p->$taf, $oldRelativeUrlSansExt) !== false) { // FIX 2: Explicitly declare UTF-8 for the DOMDocument $pagedom = new DOMDocument('1.0', 'UTF-8'); libxml_use_internal_errors(true); // add <cun> as fake root element $pagedom->loadHTML('<?xml encoding="utf-8" ?><cun>' . $p->$taf . '</cun>', LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED | LIBXML_SCHEMA_CREATE); $pagedom = $this->replaceRteLink($pagedom, $newFilename, $oldFilename, 'a', 'href'); $pagedom = $this->replaceRteLink($pagedom, $newFilename, $oldFilename, 'img', 'src'); // remove fake root element $html = str_replace(['<cun>', '</cun>', '<?xml encoding="utf-8" ?>'], '', $pagedom->saveHtml()); // FIX 3: Restore UTF-8 characters converted to entities by DOMDocument $html = $this->wire('sanitizer')->unentities($html); $p->of(false); $p->$taf = $html; libxml_clear_errors(); $p->save($taf); } } } }
  3. Amazing, this looks like the ultimate sitemap module (haven't tested yet) but as @dynweb said a role restriction should be definitely added. I guess replacing the 24th line of ProcessSitemap.module.php with the below will do the trick: 'permission' => 'sitemap-edit', 'permissions' => array( 'sitemap-edit' => 'Edit Sitemap settings' ),
  4. Now that the issue is fixed on ProcessWire 3.0.254 the module doesn't render any markup. As guest I see only a blank page. FIX: On line 51 https://github.com/Toutouwai/AccessByQueryString/blob/master/AccessByQueryString.module#L51 replace addHookBefore with addHookAfter.
  5. Avoid using Base64 images as Gmail don't support them. The only reliable method is using absolute urls.
  6. @Robin S The module doesn't work with ProcessWire 3.0.253 cause as guest if I visit the protected website getting this error: Method PageRender::matches does not exist or is not callable in this context in C:\laragon\www\mysite\wire\core\Wire.php:563. There is no issue in ProcessWire 3.0.252.
  7. Nothing that can't be handled by your module but I'm planning to add some extra details outside of table data like total counters of specific users etc. and some filters too.
  8. Thanks for the info but I ended up creating my own custom modules specifically for a project for displaying lists like users, transactions etc. It was about time to learn about MarkupAdminDataTable and it was easy 😎 thanks to the explantion of @bernhard guide.
  9. Ok found why this is happening. The code is fine as I was I able to create a user from a different template and there was no problem. I'm creating a user when order through Padloper (v1) is completed. Few days ago I've renamed the page name "padloper" from the related admin page that displays the orders and since that name is hardcoded on Padloper module that's why I was getting that weird issue.
  10. It's on localhost with ProcessWire 3.0.251 and PHP 8.3.9. I've imported yesterday's db backup and the problem is gone. I did 2 things today, creating a custom process module and creating a user from api. The module doesn't cause any issue so I repeated the process of creating a user from the api and it seems that is causing the issue. Why the following code is causing that weird issue??? // Check if order is paid if($order->pad_paid) { // Save new user if($user->isGuest()) { $u = $users->add($order->email); $u->email = $order->email; $u->pass = $order->pass; $u->ip_address = $order->pad_ip_address; $u->addRole("login-register"); $u->save(); // Save user to the order page $order->setAndSave([ 'pad_user' => $u->id ]); } }
  11. Hello! I'm suddenly getting the following error on my first login to admin, when installing/uninstalling a module and when checking for new module updates through ProcessWireUpgrade module. PHP Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in C:\laragon\www\mysite\wire\core\LanguageFunctions.php on line 232 The line 232 of wire\core\LanguageFunctions.php has this: if($encode) $value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8', $encode === true); And when this error happens, the main admin menu links Pages, Setup, Modules, Access are gone. EDIT: The following code on my template for creating user is causing that weird issue: // Check if order is paid if($order->pad_paid) { // Save new user if($user->isGuest()) { $u = $users->add($order->email); $u->email = $order->email; $u->pass = $order->pass; $u->ip_address = $order->pad_ip_address; $u->addRole("login-register"); $u->save(); // Save user to the order page $order->setAndSave([ 'pad_user' => $u->id ]); } }
  12. @ryan @diogo @jploch are you planning to upgrade also the font awesome icons? They haven't been upgraded for over a decade... Few days ago the v7 was released. Last year I've created a module that upgrades backend with the latest Font Awesome free icons (solid + brands) but I think a core upgrade would be much better integration.
  13. Btw, if there are modules or hooks that send only plain text emails like for example some notifications on LoginRegisterPro with the following hook you can force HTML on all outgoing emails and forget about those ugly emails 😎 /** * Force HTML on all outgoing emails * */ $wire->addHookBefore('WireMail::send', function(HookEvent $event) { $wireMail = $event->object; if($wireMail->body && !$wireMail->bodyHTML) { $forceHTML = nl2br($wireMail->body); // nl2br — Inserts HTML line breaks before all newlines in a string $wireMail->bodyHTML($forceHTML); } }); I guess this can get combined with your hook but for now I'm using it as separate.
  14. Thank you @bernhard for this! What if I have a LazyCron hook to send emails about expirations and want to display a call to action button on those? Should I create the button on a .mjml file then convert it to html and copy ONLY the HTML part of the button and paste it on BodyHTML of the LazyCron hook or there is a better way?
  15. Here is the solution. First, on the checkbox field (let's call it terms_privacy_checkbox) settings leave empty the "Checkbox label". On the field "Label" you can either write something for example "Terms - Privacy Policy" or leave empty (it will output field name) doesn't matter cause we gonna remove it with the following hook. $wire->addHookAfter('Page::render', function(HookEvent $event) { if($this->wire('page')->template->name != 'checkout') return; $event->return = str_replace("<span class='pw-no-select'>Terms - Privacy Policy</span>","", $event->return); }); Then with the following hook where we customize our form we can change the markup for the checkbox field too and split it to 2 divs using for example UIkit. $wire->addHookBefore('InputfieldWrapper::render', function($event) { if ($this->wire('page')->template->name != "checkout") return; $wrapper = $event->object; $terms = wire('pages')->get("template=terms"); $privacy = wire('pages')->get("template=privacy"); $defaultMarkup = array( // Check wire\core\InputfieldWrapper.php for the $defaultMarkup 'list' => "<ul {attrs}>{out}</ul>", 'item' => "<li {attrs}>{out}</li>", 'item_label' => "<label class='InputfieldHeader ui-widget-header{class}' for='{for}'>{out}</label>", 'item_label_hidden' => "<label class='InputfieldHeader InputfieldHeaderHidden ui-widget-header{class}'><span>{out}</span></label>", 'item_content' => "<div class='InputfieldContent ui-widget-content{class}'>{out}</div>", 'item_error' => "<p class='InputfieldError ui-state-error'><i class='fa fa-fw fa-flash'></i><span>{out}</span></p>", 'item_description' => "<p class='description'>{out}</p>", 'item_head' => "<h2>{out}</h2>", 'item_notes' => "<p class='notes'>{out}</p>", 'item_detail' => "<p class='detail'>{out}</p>", 'item_icon' => "<i class='fa fa-fw fa-{name}'></i> ", 'item_toggle' => "<i class='toggle-icon fa fa-fw fa-angle-down' data-to='fa-angle-down fa-angle-right'></i>", // ALSO: // InputfieldAnything => array(any of the properties above to override on a per-Inputfield basis) // Here we override the default markup for checkbox field by targeting it's name 'name=terms_privacy_checkbox' => [ 'item_label' => "", 'item_label_hidden' => "", 'item_content' => " <div class='uk-grid-collapse{class}' uk-grid> <div class='uk-width-auto'> {out} </div> <div class='uk-width-expand'> <label class='uk-form-label' for='Inputfield_terms_privacy_checkbox'> <span class='uk-text-normal'>I agree with the <a href='{$terms->url}' rel='noopener' target='_blank'>{$terms->title}</a> and the <a href='{$privacy->url}' rel='noopener' target='_blank'>{$privacy->title}</a>.</span> </label> </div> {error} </div>", ], ); $defaultClasses = array( // Check wire\core\InputfieldWrapper.php for the $defaultClasses 'form' => '', // additional clases for InputfieldForm (optional) 'list' => 'Inputfields', 'list_clearfix' => 'ui-helper-clearfix', 'item' => 'Inputfield {class} Inputfield_{name} ui-widget', 'item_label' => '', // additional classes for InputfieldHeader (optional) 'item_content' => '', // additional classes for InputfieldContent (optional) 'item_required' => 'InputfieldStateRequired', // class is for Inputfield 'item_error' => 'ui-state-error InputfieldStateError', // note: not the same as markup[item_error], class is for Inputfield 'item_collapsed' => 'InputfieldStateCollapsed', 'item_column_width' => 'InputfieldColumnWidth', 'item_column_width_first' => 'InputfieldColumnWidthFirst', 'item_show_if' => 'InputfieldStateShowIf', 'item_required_if' => 'InputfieldStateRequiredIf' // ALSO: // InputfieldAnything => array(any of the properties above to override on a per-Inputfield basis) ); $wrapper->setMarkup($defaultMarkup); $wrapper->setClasses($defaultClasses); foreach ($wrapper->children as $in) { switch ($in->name) { case 'email': $in->wrapAttr('class', 'uk-width-1-1'); $in->addClass('uk-input'); $in->attr('required', 'required'); break; case 'pad_paymentmodule': $in->wrapAttr('class', 'uk-width-1-1 uk-margin-small-top'); $in->addClass('uk-radio'); break; case 'terms_privacy_checkbox': $in->wrapAttr('class', 'uk-width-1-1'); $in->addClass('uk-checkbox'); $in->attr('required', 'required'); break; case 'customerForm': $in->wrapAttr('class', 'uk-width-1-1 uk-margin-medium-top'); $in->addClass('uk-button uk-button-primary uk-button-large'); break; default: $in->wrapAttr('class', 'uk-width-1-1'); $in->addClass('uk-width-1-1'); break; } } });
  16. No. I figured it out and I will post the solution soon.
  17. Anyone knows how to split the checkbox's input and label in 2 divs with Inputfield Markup to look like in the following screenshot? I'm using UIkit so this can be achieved like below but I can't figured out how to do this with Inputfield Markup. <div class="uk-grid-small" uk-grid> <div class="uk-width-auto"> <input id="checkbox" class="uk-checkbox" type="checkbox"> </div> <div class="uk-width-expand"> <label for="checkbox">Checkbox Label</label> </div> </div>
  18. Hello @Mikel! I've created a data table but it's only visible to superuser. How can I make it viewable to non-superuser? I see that you have the permission "data-table-view" so I've added it to the non-superuser role but still not visible.
  19. Hello @Mikel I'm testing the module and noticed 2 issues. I'm getting the following Warning x2 times when viewing the User Data Table page: Warning: Attempt to read property "type" on null in C:\laragon\www\mysite\site\modules\ProcessUserDataTable\ProcessUserDataTable.module on line 595 The Settings link on User Data Table page is broken as it has a hardcoded admin page name as "cms".
  20. @ryan On ProcessWireUpgradeCheck module I'm getting a 500 Internal Server Error and I can ONLY see the updates for the PW dev and master version. No info about the 3rd-party modules.
  21. @Juergen I just tested it and it works but now there is a new issue. On console I'm getting this error on all admin pages except the FrontendForms page module. Uncaught TypeError: $(...).imagepicker is not a function Check the initializeImagePicker function.
  22. @Juergen Problem solved. No longer getting these files on frontend. Thank you. The only problem needs to be solved is to not load them on every admin page.
  23. I'm talking about backend files that getting inserted on frontend. I removed everything (header, footer etc.) from my template and just added only the execution line of LoginRegisterPro: <?php namespace ProcessWire; echo $modules->get('LoginRegisterPro')->execute(); ?> and as you can see from the screenshot below the FrontendForms files I mentioned on the previous post are getting inserted. This happens on every form of LoginRegisterPro (login, register, edit profile, forgot password) which are all exist on the same template and triggered by the above 1 line of code. These files are also inserted on every admin page too. You're right.
  24. @Juergen the module's CSS / JS are getting executed on a page where LoginRegisterPro is executed even though I have already removed all CSS / JS from your module and the form used by FrontendForms is on a different page. EDIT: These are the files: site/modules/FrontendForms/backend/frontendforms.css?v=2.2.32-1745913193&time=1745913193 site/modules/FrontendForms/image-picker/image-picker.css?v=2.2.32-1745913193 site/modules/FrontendForms/backend/frontendforms.js?v=2.2.32-1745912921&time=1745912921 site/modules/FrontendForms/image-picker/image-picker.min.js?v=2.2.32-174591292
  25. @ryan will you consider to add an option to populate the loading="lazy" attribute to iframe tags? Although with a simple hook like below we can get the job done but it would be great if we can have it available on the module. $wire->addHookAfter('Page::render', function(HookEvent $event) { if ($this->wire('page')->template->name != "my-content") return; $event->return = str_replace("<iframe ", "<iframe loading='lazy' ", $event->return); });
×
×
  • Create New...