Jump to content


Popular Content

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

  1. 13 points
    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:
  2. 3 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.
  3. 3 points
    When you install PW for the first time choosing Uikit 3 Site/Blog Profile you feel good. You immediately understand it will take you sometime to fine tune your site, but you will not regret other popular CMS. After a short front end navigation with Uikit 3 Site/Blog Profile the theme looks simple but complete, so a great starting point. But suddenly your eyes will point at something strange … why my reserved user name which I took 10 minutes to invent … is right there in front of me: "Posted by mySecretUserName …" so that every visitor can see it ?! Uh! Let's make a step back. When you first installed PW you were asked for a user name and password. I tend to avoid generic user names like "admin" … "administrator" … but I normally build a complex user name using lowercase/uppercase/digits. If you open the post, and look at the bottom you will see that your reserved user name not only is below the post title but also in the preset data of the comment form. OK, keep calm! After a quick learning about Output Strategies and ... scrolling each file in /site/template you finally understand ... that what you are looking for is ukBlogPost() function in _uikit.php. Yes, this is the magic function that renders a blog-post, both when it is just summarized in a list of items or fully displayed in a page. The line of code that was waiting for me was: $name = $page->createdUser->name; Uh! So no mistakes, my reserved user name was going public ... After a quick course on the Admin side and reading this forum, you start to feel how PW is powerful. What we have to do to solve our problem it is simply to enhance the User template adding a publicName field to it. Let's proceed step by step. Login the Admin panel, select Setup, then Fields. Let's create a new text field named publicName, then save. Then select Setup, then Templates. In PW you can also edit system templates, but to do that you have to select the show system templates option: Once the list of system templates appears, we will select the template "user", and we will add the new field publicName, then save. Now clicking on your user name on the top you are going to open your user profile. A blank field named Public Name is now available. There we will write our public name, that.. by chance … will be "Administrator". Of course you can choose whatever you like, and any new user you are going to create will have available such a field. So each user can have a complex user name for login purposes and a public name that will be shown, for example when posting blog posts or replying to comments. Now that the new field is available we can go back to ukBlogPost() function in _uikit.php and change the code as follows: //$name = $page->createdUser->name; $name = $page->createdUser->publicName; //>>>>> REPLACE WITH THIS LINE Let's go back to the front end, and now we see that our reserved user name is no longer there: "Posted by Administrator on …". Good... I feel better. Please note that reserved user name in the comment form will be shown only for logged-in user, and you can manually overwrite it in case you have to reply a comment. Otherwise it's necessary to modify FieldtypeComments module. In particular the function render() of ContactForm.php: if($user->isLoggedin()) { //$inputValues['cite'] = $user->name; $inputValues['cite'] = $user->publicName; //>>>>> REPLACE WITH THIS LINE $inputValues['email'] = $user->email; } As I already did few other modifications to FieldtypeComments I also took the opportunity to fix that, but if you are a new PW user, please wait to modify FieldtypeComments until you are more familiar with the environment. It will be necessary to clone the module as described in the first steps of this tutorial: I hope some new user will find those information of help. Wish a good week start to everybody!
  4. 2 points
    Now this works: $module = wire('modules')->getModule('ProcessPageAdd'); $test = ($module->executeNavJSON()); return $test; This gives me the following json-output: {"url":"\/processwire\/processwire\/page\/add\/","label":"Modules","icon":"plus-circle","add":null,"list":[{"url":"?parent_id=1016&template_id=57","label":"Eine neue Leistung erstellen","icon":"plus-circle","parent_id":1016,"template_id":57},{"url":"?parent_id=1048&template_id=51","label":"Neuigkeit erstellen","icon":"plus-circle","parent_id":1048,"template_id":51},{"url":"bookmarks\/?role=0","label":"Lesezeichen","icon":"bookmark-o","className":"separator separator"}]} And these are the pages I was looking for: list":[ {"url":"?parent_id=1016&template_id=57","label":"Eine neue Leistung erstellen","icon":"plus-circle","parent_id":1016,"template_id":57},/n{"url":"?parent_id=1048&template_id=51","label":"Neuigkeit erstellen","icon":"plus-circle","parent_id":1048,"template_id":51}........ So I get: parent_id: 1016, template_id:57 and parent_id:1048, template_id:51 These are the 2 pages that I have in the shortcut menu and the IDs that I need😃 So for the moment my new dashboard has the same functionality as the add-new navigation of PW, but a little more userfriendly than the small navigation in the left corner. New shortcut items can be added via the bookmark button, so every user can add his own favorites shortcuts to make his dashboard individually (if he has the rights of course ;-).
  5. 1 point
    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 !
  6. 1 point
    Really complicated, but I will give this a try. I thought that it must be really simple to get the IDs of the pages in the shortcut navigation, but it isnt. Thanks for the tipp!!!
  7. 1 point
    @Juergen this is too much for monday! haha. But you know, looking at the config page, this list probably generated on runtime because there is also no way to delete them on the config screen, I took a look at the source code and I THINK, it's happening here, so maybe you can call executeNavJSON?: https://github.com/processwire/processwire/blob/master/wire/modules/Process/ProcessPageAdd/ProcessPageAdd.module#L151
  8. 1 point
    In case anyone is interested, cloning also doesn't update the createdUser and modifiedUser values. I have submitted an issue: https://github.com/processwire/processwire-issues/issues/927 but in the meantime, I am using: $this->addHookAfter('Pages::cloned', function(HookEvent $event) { $p = $event->arguments(1); $p->createdUser = $this->wire('user'); $p->save(array('quiet' => true)); $sql = "UPDATE `pages` SET `modified_users_id` = '".$this->wire('user')->id."' WHERE `id` = '".$p->id."';"; $this->wire('db')->query($sql); }); Modified can't be changed via the API, hence the SQL. I suppose created could also be done this way, but hopefully this is just a temporary fix assuming Ryan agrees to change the current behavior.
  9. 1 point
    Strange. According to the official docs, this should work. Maybe a caching issue? Can't you just use @import ? Try adding a Custom Editor JS Styles Set, and then follow these steps: https://processwire.com/docs/fields/ckeditor/#custom-editor-js-styles-set
  10. 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!
  11. 1 point
    Sounds like a great week 🙂
  12. 1 point
    Woah... Well... I don't use this word that often but... this is insane. In a very good and positive way.
  13. 1 point
    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 !!
  14. 1 point
    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.
  15. 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.
  16. 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.
  17. 1 point
    Moderator note: this thread is about a core feature, so I'm moving it to the General Support area of the forum. Modules/Plugins area is intended for dedicated support threads of third party modules. Thanks!
  18. 1 point
    Could be a simple issue with the paths. When site/config.php is loaded, the working directory should be site root, so you may be going way below the level you actually intended. You could try __DIR__ . '/../../libraries/vendor/autoload.php' instead, or just './libraries/vendor/autoload.php' (in case your libraries directory is in your site root – or ../ if it's below it).
  19. 1 point
    @Torsten Baldes, there has been an @todo note about adding OR-group support to InputfieldSelector since 2016. Seeing as Ryan has been doing some work on InputfieldSelector recently it might be timely to open a request for this in the requests repo to bring it back to his attention. 🙂
  20. 1 point
    We had this issue recently, it's because of the limit of Input variables in your PHP configuration. Adjusting the value of max_input_vars in your php.ini file to a larger number will increase the number of items you can save 🙂
  21. 1 point
    Thx @Robin S, I had a look to those fieldtypes and you where partially right. I removed sleepValue and deletePageField since they should never get called on a non-db fieldtype. But your runtimeonly field does actually have too few methods if you want to keep it completely out of the db. Your fieldtype creates an empty db table. Not sure if that is intended? I've invested some more time and really like this approach of building new Fieldtypes! Is really simple, see this example of a new Fieldtype called "FieldtypeNow": I renamed the base fieldtype to "BaseFieldtypeRuntime" and it really does not do anything other than providing the boilerplate. It does not even show up in the list when you create a new field in your pw installation (screenshot later). This is the current code: Actually it does only define the inputfield and add some hooks to replace the render and renderReady methods by our own implementations and define all the functions necessary to keep the db out of the game: Simple, right? 🙂 This is how the installation screen looks like: The BaseFieldtype is set as dependency, so FieldtypeNow can only be installed when the Base Fieldtype is available. Once installed, you can easily create a new field of that type: Notice that there is no Fieldtype "BaseFieldtypeRuntime" in this list as I mentioned above. You can then add your field to a template and edit any page of that template: <?php namespace ProcessWire; /** * Demo Fieldtype Extending the Boilerplate Runtime Fieldtype * * @author Bernhard Baumrock, 03.10.2018 * @license Licensed under MIT * @link https://www.baumrock.com */ class FieldtypeNow extends BaseFieldtypeRuntime { public static function getModuleInfo() { return [ 'title' => 'FieldtypeNow', 'version' => '0.0.1', 'summary' => 'Fieldtype showing the current time', 'icon' => 'code', 'requires' => ['BaseFieldtypeRuntime'], ]; } public function render() { return time(); } } Another Fieldtype rendering the content of a php file named like the field (very similar to the existing modules by @kongondo RuntimeMarkup, @Robin S RuntimeOnly and @kixe FieldtypeMarkup). You actually only have to implement the render() method, and if you need you can load scripts in the renderReady() method... This fieldtype loads files that are named like this: site/templates/FieldtypeRenderFile/{fieldname}.{templatename}.[php/css/js] site/templates/FieldtypeRenderFile/{fieldname}.[php/css/js]
  • Create New...