Jump to content


Popular Content

Showing content with the highest reputation on 07/14/2019 in all areas

  1. 6 points
    When your blog content is growing to some thousands of pages and you have comments scattered here and there, sometimes you start wondering if placing comments below each post is the best approach. Of course this totally depends on your project and contents. In my case I came to the conclusion I could provide a better user experience switching to a Forum-like solution, where discussions were organized by macro subjects and not below each individual post. Of course there are many products and services providing fully featured forum solutions, but getting only few comments per day I was reluctant to setup a dedicated forum and to deal with users' profiles. A nice thing of the comments system is that users do not need to create account and password, but simply use their email address. And here we are ... why not to setup a very basic Forum-like solution using PW Comments? But please do not get too excited… we will just use comments in a way that looks-like-a-forum. I think this solution makes sense if you have a limited number of comments per day spread on some topics. If you need to deal with high discussions traffic with several users ... do it with a fully featured forum solution !! To implement this Forum-like solution we will take benefits of (1) PW pages/templates flexibility (why you should be here otherwise…), (2) core module FieldtypeComments, (3) Uikit 3 Site/Blog Profile, (4) some of the tutorials I recently released about PW Comments (listed at the end). OK, let's start. Login into the Admin panel, select Setup, and then Fields. Let's create a checkbox field named "sticky" that we can use to keep some forum subjects on top of the communities. Now let's move to Setup, Template. We will create a new template with name "communities'. In addition to "title" field, we will add also "body" and "sidebarRight" fields (already available in the profile): Then we create a template, that we will use for individual communities, with name "community". In addition to "title" field, we will add "date", "body", "images", "comments" fields (already available in the profile) and the "sticky" field we have just created. If you wish, as I did, you can also associate some category fields. If you use Multi-Language is a good idea to use the field "date", as ,differently from createdStr, it will automatically return a locale-formatted date as you defined in the field. Now that we have created the templates, we need to customize them. Reopen the "communities" template. In the Family tab: allow the template to have children, allow only one page with this template, select "community" as only allowed template for CHILDREN. Then in the URLs tab: select allow page numbers. This will return a paginated list of communities. We reopen the "community" template. In the Family tab: do not allow the template to have children, allow to create new pages, select "communities" as only allowed template for PARENT. Now in the URLs tab: select allow page numbers. This will be necessary to create paginated comments. Let's go to the page-tree, under Home we will create a new page named "Community" using the templates "communities" (note the final s), this will be the page listing all the communities. Under the Community page, we will create the individual communities. Give the pages the name you wish and use the template "community" (note w/o the final s). It may be good creating one with the name "New Forum Requests" checking its "sticky" field so that it remains on top. As to implement this Forum-like solution, the comments pagination is a must, at this stage you will have to implement it as described in this tutorial: Now we are ready for coding (very little!) the php templates. We need to associate php files to the two templates we have created. In site/templates create two new php files communities.php and community.php. Open the template blog.php and copy its content to communities.php, then repeat the same operation copying the content of template blog-post.php to community.php. Great! We are few steps away from our Forum-like solution. Modify communities.php as follows: ... echo ukHeading1(page()->title, 'divider'); echo page()->body . '<br><hr>'; //>>>>> ADD THIS LINE //$posts = page()->children('limit=10'); //echo ukBlogPosts($posts); $posts = page()->children('sort=-sticky, sort=title, limit=10'); //>>>>> ADD THIS LINE echo ukBlogPosts($posts, ['moreText' => '', 'moreIcon' => '']); //>>>>> ADD THIS LINE ... Then modify community.php as follows: // blog post content echo ukBlogPost(page()); // comments if($page->hasField('comments')) { //>>>>> ADD THIS LINE $comments = page()->comments; // comment list if(count($comments)) { //echo ukHeading3("Comments", "icon=comments"); echo ukComments($comments->find("sort=-created"), ['paginate' => true]); //>>>>> ADD THIS LINE - READ PAGINATION TUTORIAL (NEEDED) echo '<hr>'; } // comment form $gdpr = __('I agree with the processing of my personal data. I have read and accept the Privacy Policy.'); //>>>>> ADD THIS LINE - READ GDPR TUTORIAL (OPTIONAL) echo ukHeading3(__('Join the discussion'), "icon=comment"); echo ukCommentForm($comments, ['labels' => ['gdpr' => $gdpr]]); //>>>>> ADD THIS LINE - READ GDPR TUTORIAL (OPTIONAL) } //>>>>> ADD THIS LINE Very good (hope so...). Now let's see the result. When browsing to the Community page we will get the list of the communities. In my example I decided to keep sticky the one where users can submit suggestions for new forum subjects. Selecting one of the communities we have created, we are going to see (1) a description of the community, (2) a paginated list of comments, (3) and the comment form at the bottom. Please note that in this picture pagination is kept with a limit of three items just to fit the image … It makes sense to have 10-15-20 comments per page depending on your preferences. And we are done, here it is. If you wish you can implement some additional features as described in the tutorials below. Not mandatory but probably makes good sense to enable the honeypot field as described in this tutorial as anti-spam measure: If you have the "pleasure" to deal with GDPR matters, here is described how to add a privacy checkbox to your comment form: and finally if you wish your Forum-like solution to be Multi-Language here it is what to do: I hope you enjoyed and wish you a nice week-end ! PS: it's a couple of tutorials I miss the emoj … hope they will come back in this forum soon !!
  2. 4 points
    For those who have the "opportunity" to deal with GDPR … and are implementing PW FieldtypeComments it's worth making a Privacy assessment. When a visitor submits a comment, is going to visibly provide personal data: the commenter's name (or nickname) and email. Going a bit deeper, we can see that a cookie named CommentForm is created, it stores visitor's name and email, with session long duration. If you wish more details, this cookie is entirely managed at javascript level in comments.js. Of course this cookie is very helpful as it pre-fills the comment form with commenter's information to speed up future comments submissions. Let's make a step further and have a look to field_comments table inside the database. As you can see (PhpMyAdmin), in addition to the commenter's name (cite) and email, FieldtypeComments is also tracking the commenter's IP address. Uh..! Should we ring an alarm bell ... and remove all the comments from our blog … ? Of course not ... The simplest approach would be to make sure your privacy policy and cookie policy are taking into account all those aspects, including IP tracking, to make your visitors aware which personal data you process, why and for how long do you keep them. In light of that, it gets important to ask the commenter an explicit consent to personal data processing by a checkbox when submitting the comment form. More specifically regarding IP tracking you may ask yourself if you really need to track the commenter's IP address. You should also get information if you-have-to-do-it because of your country laws. If you concluded that you are not interested or obliged to track commenter's IP address, how to disable it ? Commenter's IP address is gathered in function processInput() of CommentForm.php in FieldtypeComments module. $comment->ip = $this->wire('session')->getIP(); Unfortunately I could not find any preset option to stop it, but (... obviously!) it is sufficient to change it to: $comment->ip = ''; However do not forget not to modify the original FieldtypeComments in wire/modules/Fieldtype/FieldtypeComments, but copy it to site/modules/FieldtypeComments. Please refer to the initial part of this tutorial for the detailed steps to duplicate the module and make PW aware of which module version to use. An alternative to entirely disable ip tracking could be to anonymize it. $comment->ip = A::anonymizeIp(wire('session')->getIP()); Through the function here below. Please note, in this function I could not test if ipv6 anonymizing works as expected. class A { public static function anonymizeIp(string $ip) { $ipv4Mask = ""; //strip last octect $ipv6Mask = "ffff:ffff:ffff:0000:0000:0000:0000:0000"; //strip last 80 bits $ipLen = strlen(inet_pton($ip)); $ipMask = $ipLen == 4 ? $ipv4Mask : ($ipLen == 16 ? $ipv6Mask : ''); return inet_ntop(inet_pton($ip) & inet_pton($ipMask)); } ) And here we are! Happy Privacy to everybody !
  3. 3 points
    Dashboard Tasks MD COLLABS, MaxDev Collaboration & Sharing Tool is a simple management task module; a plugin runs on Processwire CMF Framework. Available here at https://github.com/sjahrazad/DashboardTasks This module allows you to track interactions in your team through your Email application; furthermore, you can collaborate and share your task instantly from the web site. This module modified from Kongondo Dashboard Notes at https://processwire.com/talk/topic/20980-dashboard-notes/ Install 1. Place the module files in /site/modules/DashboardTasks/ 2. In your admin, click Modules > Check for new modules 3. There are two modules, the main module is DashboardTasks, and the other one DashboardDocs is an optional module in case you want the users to attach files to their task. 4. Install DashboardDocs to use both modules, or install DashboardTasks only without the document attachment. User Roles There are three roles for this module, task-user (co-worker), task-owner (task creator) and task-manager. Demo Users The installer created five demo users, task-manager, task-owner and three task-coworkers. For the first time log-in user, before using the module, a task manager role required to configure the Global Settings. user name: task-manager, password: task-manager, email: task-manager@yourdomainname user name: task-owner password: task-owner, email: task-owner@yourdomainname user name: task-coworker1 password: task-coworker1, email: task-coworker1@yourdomainname user name: task-coworker2 password: task-coworker2, email: task-coworker2@yourdomainname user name: task-coworker3 password: task-coworker3, email: task-coworker3@yourdomainname Change those emails with your test emails. Task Types There are three types available for the new task creation. First, is the Notes type. Use this type if you want to share your notes or collaborate the ideas to your members. The second type is the core of this module, a Task Scheduler type with start date and due date of the task. If you click the Required Job Acceptance from your task settings, then this task type will become an enquiry or job offer task type. The third type is the Reports or Private Notes type. Use this type for your private record or might be you share it to the selected members in your team. Usage Scenario You can use this module for numerous tasks management purposes, from just a shared idea up to enquiry request type. Email or SMS is the primary interface for the user in this module. The user can decide either respond to that email request and log in to the system or just read it in their mailbox. If there is no action required from the recipient, then it is not compulsory to log in to the system as well. Responses to the submitted task also will be sent out to the task creator email as well. For example, your company use a Call Centre service to capture your customer's enquiries, where the messages will be sent out to your contractors or service providers. In this case, your role here is the Task Manager, the call centre agent's role become the Task Owner, someone who created the task and your contractors or service providers are the Task Users. Once a contractor received the request and accepted the enquiry's offer, this contractor assigned as the job provider for that task. The other scenario usage, for example, you're a property manager who will process your tenant request for fault enquiry to your tradesperson group. Or, a lecturer who wants to arrange a research group with some students.. the list goes on ... CSS CSS Grid doesn't work in some old browsers. You need to adjust the CSS under Less folder if you want to use this module for old browsers. <details> tag is not working in IE or Edge browser. SMS If you want the output sent to SMS and Email, you have to add your SMS Provider API to the ProcessDashboardTasks.module. And add your mobile users' array to the SaveTask and SaveTaskReply function.
  4. 2 points
    Hey folks! Took a couple of late nights, but managed to turn this old gist of mine into a proper module. The name is SearchEngine, and currently it provides support for indexing page contents (into a hidden textarea field created automatically), and also includes a helper feature ("Finder") for querying said contents. No fancy features like stemming here yet, but something along those lines might be added later if it seems useful (and if I find a decent implementation to integrate). Though the API and selector engine make it really easy to create site search pages, I pretty much always end up duplicating the same features from site to site. Also – since it takes a bit of extra time – it's tempting to skip over some accessibility related things, and leave features like text highlighting out. Overall I think it makes sense to bundle all that into a module, which can then be reused over and over again 🙂 Note: markup generation is not yet built into the module, which is why the examples below use PageArray::render() method to produce a simple list of results. This will be added later on, as a part of the same module or a separate Markup module. There's also no fancy JS API or anything like that (yet). This is an early release, so be kind – I got the find feature working last night (or perhaps this morning), and some final tweaks and updates were made just an hour ago 😅 GitHub repository: https://github.com/teppokoivula/SearchEngine Modules directory: https://modules.processwire.com/modules/search-engine/ Demo: https://wireframe-framework.com/search/ Usage Install SearchEngine module. Note: the module will automatically create an index field install time, so be sure to define a custom field (via site config) before installation if you don't want it to be called "search_index". You can change the field name later as well, but you'll have to update the "index_field" option in site config or module settings (in Admin) after renaming it. Add the site search index field to templates you want to make searchable. Use selectors to query values in site search index. Note: you can use any operator for your selectors, you will likely find the '=' and '%=' operators most useful here. You can read more about selector operators from ProcessWire's documentation. Options By default the module will create a search index field called 'search_index' and store values from Page fields title, headline, summary, and body to said index field when a page is saved. You can modify this behaviour (field name and/or indexed page fields) either via the Module config screen in the PocessWire Admin, or by defining $config->SearchEngine array in your site config file or other applicable location: $config->SearchEngine = [ 'index_field' => 'search_index', 'indexed_fields' => [ 'title', 'headline', 'summary', 'body', ], 'prefixes' => [ 'link' => 'link:', ], 'find_args' => [ 'limit' => 25, 'sort' => 'sort', 'operator' => '%=', 'query_param' => null, 'selector_extra' => '', ], ]; You can access the search index field just like any other ProcessWire field with selectors: if ($q = $sanitizer->selectorValue($input->get->q)) { $results = $pages->find('search_index%=' . $query_string . ', limit=25'); echo $results->render(); echo $results->renderPager(); } Alternatively you can delegate the find operation to the SearchEngine module as well: $query = $modules->get('SearchEngine')->find($input->get->q); echo $query->resultsString; // alias for $query->results->render() echo $query->pager; // alias for $query->results->renderPager() Requirements ProcessWire >= 3.0.112 PHP >= 7.1.0 Note: later versions of the module may require Composer, or alternatively some additional features may require installing via Composer. This is still under consideration – so far there's nothing here that would really depend on it, but advanced features like stemming most likely would. Installing It's the usual thing: download or clone the SearchEngine directory into your /site/modules/ directory and install via Admin. Alternatively you can install SearchEngine with Composer by executing composer require teppokoivula/search-engine in your site directory.
  5. 1 point
    I've been in Minnesota all week for a family reunion and only a few minutes at the computer every day, so I don't have a core update or anything worthwhile to write about this week. But now I'm headed back home so will be back to a regular schedule next week. Hope that you have a great weekend!
  6. 1 point
    A sneak preview of a new page builder concept that I'm close to completing. I'll write more about this in coming weeks, but this video demonstrates a lot of unique things going on:
  7. 1 point
    Thanks for the tutorial, Edison. It might be useful if the getIP() method in wire/core/sessions.php#L707 were made hookable. This would allow you to add a hook to ready.php to handle redaction, rather than having to clone the module.
  8. 1 point
    Great module! Thank you for the update.
  9. 1 point
    Both the list on the Modules page and the fieldtype select on field edit screen expect fieldtype module names to start with "Fieldtype". BaseFieldtypeRuntime starts with "Base", so it's grouped under "Base" on the Modules page, and also not included in the fieldtypes (wire)array managed by the core (see /wire/core/Fieldtypes.php).
  10. 1 point
    Thanks @elabx The module allows to fallback to fields using placeholders. For example, if your page has a field lead_text, you can set the default value of the meta description to {lead_text}. If the content editor omits the meta description of a page, it will fallback to the lead text. It is not possible to fallback to multiple fields though. Does this answer your question? Cheers
  11. 1 point
    You're on a roll! Thanks for all these tutorials, and a very good weekend to you, too! 👍🏆🎆
  12. 1 point
    Thanks a lot to Kongondo and Szabesz for this module. I have a small project on a university website, where they required quite simple task management for their internal research team. They want all actions triggered through emails and SMS because it is not easy to expect the team always log in to their website. I did a quick development based on this module and will share and post it in a new thread.
  13. 1 point
    Nice enhancement to the file filtering in the File Editor panel thanks to @tpr that lets you arrow key up and down through results and Enter to open.
  14. 1 point
    I'm close to releasing my new module called RockMarkup which will be similar to @kongondo's and @kixe's markup modules. The module is already on github and ready to play with: https://github.com/BernhardBaumrock/RockMarkup Unfortunately I have a bug that I can't seem to find. When a field is placed in a template and visibility is set to "closed + AJAX load" the field does not work at all: Would be great to get some help with this one! URL for installation of the module: https://github.com/BernhardBaumrock/RockMarkup/archive/master.zip
  15. 1 point
    While working on optimizing Comments field for my blog, I noticed it could have been useful to have a GDPR checkbox in the form, to get privacy acceptance before a comment is submitted. At the beginning I though to inject the checkbox processing the rendered comment form, but as I already modified FieldtypeComments to create a Language field, I decided to continue on that road to add the GDPR checkbox. We will not modify the original FieldtypeComments in wire/modules/Fieldtype/FieldtypeComments, but copy it to site/modules/FieldtypeComments. Please refer to the initial part of this tutorial for the detailed steps to duplicate the module and make PW aware of which module version to use. Now that FieldtypeComments is duplicated, we can proceed with the necessary modifications. Inside the module there are 14 files, but do not worry ... only ContactForm.php and (optionally) comments.css will have to be modified. First we will modify the $options class property of ContactForm.php to add a new 'gdpr' label. Later we will use this option to pass the label's text associated with the checkbox. protected $options = array( … 'labels' => array( 'cite' => '', // Your Name 'email' => '', // Your E-Mail 'website' => '',// Website 'stars' => '', // Your Rating 'text' => '', // Comments 'submit' => '', // Submit 'starsRequired' => '', // Please select a star rating 'gdpr' => '', // >>>>> ADD THIS LINE ), As a second step it will be necessary to create the markup of the checkbox and of its label. We will do that by modifying function renderFormNormal() in ContactForm.php. Uikit 3 Site/Blog Profile is indirectly calling this function, so for my purpose it was enough. In case your application is using threaded comments, it will be necessary to modify also renderFormThread(). "\n\t\t<textarea name='text' class='required' required='required' id='{$id}_text' rows='$attrs[rows]' cols='$attrs[cols]'>$inputValues[text]</textarea>" . ... "\n\t</p>" . "\n\t<p class='CommentFormGdpr {$id}_gdpr'>" . //>>>>> ADD THIS BLOCK - START "\n\t\t<input class='uk-checkbox' type='checkbox' name='gdpr' value='checked' required='required'>" . "\n\t\t<label for='{$id}_gdpr'>$labels[gdpr]</label>" . "\n\t</p>" . //>>>>> ADD THIS BLOCK - END $this->renderNotifyOptions() . ... The last ContactForm.php modification will include our checkbox in processInput() to block comments submissions if GDPR checkbox is not filled. Please note this will operate in case you do not place "required" in the <input> directive. ... $errors = array(); foreach(array('cite', 'email', 'website', 'stars', 'text', 'gdpr') as $key) { //>>>>> ADD 'gdpr' in the array ... Now let's see how to call the modified form. If you are using Uikit 3 Site/Blog Profile you will have simply to modify the template file where ukCommentForm() is called (example: blog-post.php template). There we will prepare our checkbox message and pass it to ukCommentForm() as an argument option. echo ukHeading3(__('Join the discussion'), "icon=comment"); $gdpr = __('I agree with the processing of my personal data. I have read and accept the Privacy Policy.'); echo ukCommentForm($comments, ['labels' => ['gdpr' => $gdpr]]); However, if you are using comments in multiple template files, it makes more sense to directly modify ukCommentForm() presetting the new options inside the function body: $defaults = array( 'headline' => '', 'successMessage' => __('Thank you, your comment has been posted.'), 'pendingMessage' => __('Your comment has been submitted and will appear once approved by the moderator.'), 'errorMessage' => __('Your comment was not saved due to one or more errors.') . ' ' . __('Please check that you have completed all fields before submitting again.'), // >>>>> SEE THE HONEYPOT TUTORIAL 'requireHoneypotField' => 'email2', //>>>> ADD THESE FOUR LINES 'labels' => array( 'gdpr' => __('I agree with the processing of my personal data. I have read and accept the Privacy Policy.'), ), ); Before testing, we will modify the file comments.css adding these two directives (that's purely optional): .CommentFormGdpr input[type=checkbox] { background-color: white; } .CommentFormGdpr label { padding-left: 10px } Now let's test our form. Once it is filled with our data and comment it will look like this: If the user is pressing the submit button without accepting the GDPR checkbox, the comment will not be submitted and an error is displayed (in case you have used "required" in <input> you get this tooltip box, otherwise you will get an alert message): Now we accept the box After acceptance and submission, the comment form will be successfully sent. The standard success message is shown and the form is again displayed empty (with just cite and email pre-filled) ready for a next comment submission. Again I hope you will find some useful hint with that.
  16. 1 point
    For the last couple months, I've been working on a module that does exactly this. It's not a site profile, it's not a theme. I don't know what term would accurately describe it, but its a ProcessWire module that's an opinionated, update-able starting point, oriented towards developers, and brings in a bunch of boilerplate like: an installer that will create fields, templates, pages, hannacodes; it runs through a thorough check before doing anything that may result in an error (module installation errors are aggravating; i'm testing it very thoroughly) the installer will rename your 'templates' dir to something temporary, and then copy a starting 'templates' folder that's prepped for the module (you should only do this on dev) if you try to add it to an existing site with a bunch of data, it will work as long as there are not collisions in some fields and templates; if there are, the module won't install and tell you what you need to change around to allow it to install establishes some new $config variables ('env', 'disableTemplateCache', a few others) built with UIkit 3 in mind, but not hardcoded to it a menu builder based on Repeaters with its own Process Module has its own seo+og+twitter+sitemap metadata fields and uses Profields FieldGroup since that is the best module for handling such a grouping has it's own templates inside the module which can be used, or overridden in /site/templates/; this includes blog sitemap.xml maintenance search in addition to template files being able to be overridden, partial files can be overridden too! some module configuration fields (site_name, maintenance, etc.) the module has documentation and other statistics built into it for easy reference takes full advantage of setting() and markup regions; applies attributes like UIkit 'uk-grid' and other data attributes without "touching" the html; keeps the module flexible and easily allows you to rip out UIkit and swap it for another CSS framework (Bootstrap 4); you'll never need to touch edit the _main.php file because of how regions has been set up has it's on RepeaterMatrix fields with boilerplate matrix-types (headline, text, slideshow, etc. etc.); if the user makes new custom matrix types and a later version of my module brings in a new matrix-type, it will update the RepeaterMatrix field and merge it correctly (tricky to do!); the matrix types use many of the same base fields, thereby allowing you to switch from one matrix type to another without data being destroyed (this was only possible as of 2 weeks ago with the new matrix update) to avoid creating a bunch of 1-off fields for the matrix field for block configuration, it uses the new and quite amazing Mystique fieldtype in a unique way (this was tricky to do); this module is critical to establishing a page-builder that is clean (this was only possible as of April 2019 since the module is brand new) brings in PW's debugger to the frontend (brings in jQuery UI); can be disabled all field and template names don't use any prefixes; this would allow you to dump the module one day in the future if you don't like it, without having a bunch of field and template names that sound too specific to the module Laravel Mix based asset compiler pre-configured with UIkit works with FormBuilder and other modules I often use; works and may require certain Pro modules; eliminates the need for any modules that do blogging, menu building, sitemap, maintenance or seo since this module does it using native ProcessWire login/logout/account/register templates it may include a 'collection' generator for common things like events, products, people, properties, along with some templates for those. don't like the templates my module provides? then just create your own template file in /site/templates/the-template-file.php which will override /site/modules/my-module-name/templates/the-template-file.php Right now I just started building a few sites with it (spent the last 2 months developing it) which will hammer it out further. I will release it late summer, early fall.
  17. 1 point
    Hi! Been doing some basic Twilio implementation for a client to enable them to automatically send text messages to registered users on page publish. As an upshot, I thought I would strip out the site specific work and stick up on github here: https://github.com/benbyford/TwilioChannels This modules pulls in the Twilio APi and enables you to send SMS messages from your front or backend. Send SMS message Truncate message to single message character limit Auto-select number from range of numbers depending on $To number country of origin–this enables you to send messages with a local number to that user if one added to the config. Templates usage: $twilio = $modules->get("TwilioChannels"); $twilio->sendSMS($toNumber, $message);
  • Create New...