Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/03/2017 in all areas

  1. Headings Case A plugin for CKEditor fields in ProcessWire CMS/CMF. Adds a toolbar button for changing the case of all headings or selected headings between sentence case and title case. This is useful when you are copy/pasting text from a document that has been supplied with an inconsistent or incorrect system of capitalisation. Installation The plugin folder must be named "headingscase" – if needed, rename the folder to remove the "-master" suffix added by GitHub. Copy the "headingscase" folder to /site/modules/InputfieldCKEditor/plugins/ In the field settings for each CKEditor field that you want to activate the plugin for: Check the "headingscase" checkbox at Input > Plugins > Extra Plugins Add "HeadingsCase" at Input > CKEditor Settings > CKEditor Toolbar Usage To change the case of all headings, click the toolbar button with no text selected in CKEditor. The first click applies sentence case; the second click applies title case. To change the case of a single heading, select all or part of the heading in CKEditor before clicking the toolbar button. There can be situations where the results need manual correction: proper names, acronyms, etc. Exceptions for small words Certain short English prepositions and conjunctions (three letters or less) are excluded from capitalisation when title case is applied. Edit the exceptions array in the plugin source code if you want to customise this list of exceptions. https://github.com/Toutouwai/headingscase
    8 points
  2. I suspect that what is actually happening is that the 'normal' browser and 'incognito' mode are caching two different versions of the page, the 'normal' probably being older. Try a completely different browser and see what happens. BTW you could also try changing your code to $meta_title = $page->get('meta_title|title'); which should do the same thing. (Coz that ternary is hideous and unnecessary ) This won't actually help with the current problem, but is much nicer code.
    3 points
  3. To solve this you need to look at the code for each method you are considering hooking and ask yourself things like: What class is the method in? Does the method fire when I need it to? Does the method have an argument or return value that I need to use in my hook? So you are considering hooking ProcessLogin::afterLogin() or Session::loginSuccess(). When you look at afterLogin() you see: It is a method of ProcessLogin, a Process module that handles the PW login form. So it is only going to fire if a user logs in via the core PW login form. Maybe that isn't what you want if you are using a custom login form or logging in users via the API as part of some script. It depends on what you are doing. The method comments in the source code say it is only intended for when a superuser logs in, which could give you a clue if it is the best method to hook or not. It has no arguments that could be useful to quickly tell you things about the user who has logged in (although you could still get the $user object in other ways). So chances are Session::loginSuccess() is going to be a better option because it is a method of Session, so more closely connected to the current user session regardless of how they logged in. And it conveniently has the $user object as an argument so you can easily check properties of the user such as name, role, etc, in your hook.
    2 points
  4. Afternoon all, (or good morning or good night to those of you in other time zones) I am finally getting a chance to sink my teeth into ProcessWire (already purchased the Form Builder and ProFields) and I needed to make sure the output of one of my fields did not contain any curly quotes that my browser randomly changes regular quotes to when I'm editing the field. So I decided to try my hand at creating a Textformatter module to do just that. TextformatterReplaceCurlyQuotes is very simple but it's exciting for me to feel like I am contributing back to this great community. It was also nice for me to finally use my GitHub account as well...haha Anyway, I'm submitting it to the module directory and needed to post in a thread about it and here it is! http://modules.processwire.com/modules/textformatter-replace-curly-quotes/
    2 points
  5. See if the template's "Name format for children" field is setup to output a date (Family tab)
    2 points
  6. Very nice! It will be extremely useful in some scenarios. Thank you, @Robin S!
    2 points
  7. Oh no ! Cool things need time to be done. The difference between mediocrity and quality, is, frequently, the addition of time to talent, and work. But I am patient... Thank you again.
    2 points
  8. OAuth2Login for ProcessWire A Module which give you ability to login an existing user using your favorite thrid-party OAuth2 provider (i.e. Facebook, GitHub, Google, LinkedIn, etc.).. You can login from the backend to the backend directly or render a form on the frontend and redirect the user to a choosen page. Built on top of ThePhpLeague OAuth2-Client lib. Registration is not handled by this module but planned. Howto Install Install the module following this procedure: - http://modules.processwire.com/modules/oauth2-login/ - https://github.com/flydev-fr/OAuth2Login Next step, in order to use a provider, you need to use Composer to install each provider ie: to install Google, open a terminal, go to your root directory of pw and type the following command-line: composer require league/oauth2-google Tested providers/packages : Google : league/oauth2-google Facebook: league/oauth2-facebook Github: league/oauth2-github LinkedIn: league/oauth2-linkedin More third-party providers are available there. You should be able to add a provider by simply adding it to the JSON config file. Howto Use It First (and for testing purpose), you should create a new user in ProcessWire that reflect your real OAuth2 account information. The important informations are, Last Name, First Name and Email. The module will compare existing users by firstname, lastname and email; If the user match the informations, then he is logged in. ie, if my Google fullname is John Wick, then in ProcessWire, I create a new user Wick-John with email johnwick@mydomain.com Next step, go to your favorite provider and create an app in order to get the ClientId and ClientSecret keys. Ask on the forum if you have difficulties getting there. Once you got the keys for a provider, just paste it into the module settings and save it. One or more button should appear bellow the standard login form. The final step is to make your JSON configuration file. In this sample, the JSON config include all tested providers, you can of course edit it to suit your needs : { "providers": { "google": { "className": "Google", "packageName": "league/oauth2-google", "helpUrl": "https://console.developers.google.com/apis/credentials" }, "facebook": { "className": "Facebook", "packageName": "league/oauth2-facebook", "helpUrl": "https://developers.facebook.com/apps/", "options": { "graphApiVersion": "v2.10", "scope": "email" } }, "github": { "className": "Github", "packageName": "league/oauth2-github", "helpUrl": "https://github.com/settings/developers", "options": { "scope": "user:email" } }, "linkedin": { "className": "LinkedIn", "packageName": "league/oauth2-linkedin", "helpUrl": "https://www.linkedin.com/secure/developer" } } } Backend Usage In ready.php, call the module : if($page->template == 'admin') { $oauth2mod = $modules->get('Oauth2Login'); if($oauth2mod) $oauth2mod->hookBackend(); } Frontend Usage Small note: At this moment the render method is pretty simple. It output a InputfieldForm with InputfieldSubmit(s) into wrapped in a ul:li tag. Feedbacks and ideas welcome! For the following example, I created a page login and a template login which contain the following code : <?php namespace ProcessWire; if(!$user->isLoggedin()) { $options = array( 'buttonClass' => 'my_button_class', 'buttonValue' => 'Login with {provider}', // {{provider}} keyword 'prependMarkup' => '<div class="wrapper">', 'appendMarkup' => '</div>' ); $redirectUri = str_lreplace('//', '/', $config->urls->httpRoot . $page->url); $content = $modules->get('Oauth2Login')->config( array( 'redirect_uri' => $redirectUri, 'success_uri' => $page->url ) )->render($options); } The custom function lstr_replace() : /* * replace the last occurence of $search by $replace in $subject */ function str_lreplace($search, $replace, $subject) { return preg_replace('~(.*)' . preg_quote($search, '~') . '~', '$1' . $replace, $subject, 1); } Screenshot
    1 point
  9. A few references to Hooks: https://processwire.com/api/hooks/ https://somatonic.github.io/Captain-Hook/index.html https://github.com/adrianbj/TracyDebugger/tree/master/panels/CaptainHook http://www.flamingruby.com/blog/using-hooks-to-alter-default-behavior-of-processwire/ https://webdesign.tutsplus.com/tutorials/a-beginners-introduction-to-writing-modules-in-processwire--cms-26862
    1 point
  10. This is deliberate and Ryan has talked about it but I don't have a link handy. Probably because there can be situations where a field contains a lot of data in which case the user should be notified of a problem but not have all their work thrown out. See this example from @Soma where he shows how you can set a field back to its previous value when you want to reject a submission:
    1 point
  11. Your module should be autoload in order to use that hook. See the autoload options for the getModuleInfo() method: https://processwire.com/api/ref/module/
    1 point
  12. Here is a simple hook I put together to allow for a custom redirect when a page is not viewable: /** * Automatically redirects users to the login page if they do not have view access to a page. To use, set "Show a 404 Page" in your template's Access settings. */ wire()->addHookBefore('ProcessPageView::pageNotFound', function($e) { $page = $e->arguments[0]; if($page === null || $page instanceof NullPage) return; // This was a real 404, not caused by page access (have to check for NullPage, not just null as implied in ProcessPageView docs) $e->session->redirect($this->pages->get(1)->url, false); // Redirect to the home page (login) }); This solves my immediate need. I can then hook Page::viewable() as needed and let PW take care of the rest. I'm hoping @ryan may have some guidance on all of this.
    1 point
  13. @AndZyk - Thanks a lot, meanwhile I got it up and running. No surprise that it's more or less nearly the same as your last posted solution. <?php $albums = $page->repeater_gallery->getRandom(4); if (count($albums)) { foreach($albums as $album) { $image = $album->images_album->getRandom(); if ($image) { $imageUrl = $image->url; // Output } } } ?> The only flaw with this (for my special need) is, that if there are less albums as specified in the 'getRandom()' method, you do not get 4 images displayed. But since this will rarely occur I can live with it in the first place. Regards, Jochen
    1 point
  14. i don't know what the code does exactly, so if you also don't understand it in detail you have 3 options wait and hope that somebody else helps you you invest some time, learn something about REGEX and try to find a way that prevents the module of minifying your comments buy procache for 49$ and be happy (for 1 site) and benefit of a lot more options and improvements that it offers (or pay 169$ for unlimited sites)
    1 point
  15. Thanks for sharing! Installed it, works great
    1 point
  16. @AndZyk - Thanks for your reply, the 'getRandom()' method is well known, but I think with your solution I only get 4 randomly choosen ALBUMS and not the desired 4 IMAGES out of ALL ALBUMS. But maybe I didn't grasped it right ... @szabesz - Thank you for the link, I've already seen this post but was a bit distracted by the JS an slideshow discussion in there. Maybe I can extract some parts to solve my problem. As far as I can see, a possible solution is to randomly choose a subset of 4 albums and in the next step select 1 ( only one) image out of all the images in the image field of each choosen album - hmmm ... Any further tips? Regards, Jochen
    1 point
  17. feuerwehr-teisnach.de ProcessWire 3.0.62 Screenshots show the management of operations, where they can choose the date, age-group, vehicles in operation and they can write a text and put some gallery into it. Modules: Uikit v3 admin theme Auto Smush Markup Sitemap XML Pagetree Add New Childs Reverse Upgrades Checker Simple Contact Form CSS (SASS) & JSS compression with: grunt-sass grunt-uglify grunt-contrib-cssmin Libraries: UiKit 2 jQuery Owl Carousel hamburgers
    1 point
  18. Welcome @jothanne, you could use getRandom for this task: <?php foreach ($page->repeater_gallery->getRandom(4) as $item) { // Your output } Regards, Andreas
    1 point
  19. Hello @jothanne and welcome to the forums! Are you looking for something like this?
    1 point
  20. Yep, it is worth spending the time on this stage, I 100% agree! This is the key to get to speed with ProcessWire based development.
    1 point
  21. Hi, just a hint: I do not yet have much experience in this but for a similar (but not exactly same) use case I use @adrian's PageProtector module which supports locking down all Unpublished and/or Hidden pages just by clicking two checkboxes. I use it to protect areas of the website which are not yet ready to be seen by the public. Of course in my case Published pages should be accessible by guests, but you might want to take a look at the module's code to see how he did it so that you can extend it to Published pages as well:
    1 point
  22. Yes, I had a look into, 2 days ago. And...well... I am not ready I will follow your advice: understand the ''normal'' logic of PW, instead of trying to apply another (CMS) logic, just to stay in the confort zone. Thank you !
    1 point
  23. Have some fun with it. There's no magic, it's all in the docs. Go to the docs, read, test, read some more, test again. This was a total boost for me at the beginning. The docs are excellent and explain a lot of things. For example, you could start here: https://processwire.com/api/variables/pages/ What I'm saying is, the help pages link so well together that every time new questions are kicked up, the answer is just a few clicks away. And this forum is phenomenal for support. Stick with it, you'll be able to make some cool things in no time. Once you find a way that suits you in terms of organising your data in your site, the templates, fields etc... then it's just a matter of getting stuck into the docs to find a way to print these values to a webpage. Further in, you'll probably want to do some more complex things with the data, but deal with that when you get there.
    1 point
  24. This topic reminded my on my tests with reference based access control. I don't know about performance / production usability... But maybe You would take a look. https://bitbucket.org/pwFoo/accessbyreference/src/23e6a3597028da4021e3e348e4222a3ad77685a9/AccessByReference/AccessByReference.module?at=master&fileviewer=file-view-default Manage view / edit permissions based on a reference chain page -> group -> user. Wow... it's three years old... So it's untested with PW versions newer than three years
    1 point
  25. At first I thought this is a bug and double checked all my role permission settings : ) So, another +1 for having the delete button optionally visible for other roles. I think this should be consistent and convenient.
    1 point
  26. So I restructured the code a bit and also added some validation and sanitising, and the part that did not work before ($np->set($f->name, $form->get($f->name)->value);) started working Did I do the validation and sanitising parts correctly? Or are there more efficient/better ways of doing this? Here's the fully working code: $page_id = (int) $input->post->select_product; // page ID if ($page_id) { $p = $pages->get($page_id); $template = $p->template->name; // this is the template where we will get the fields from // make a form $form = $modules->get('InputfieldForm'); $form->method = 'post'; $form->action = './'; $form->attr("id+name",'subscribe-form'); // add the page's fields to the form $fields = $p->fieldgroup; foreach ($fields as $field) { $inputfield = $fields->{$field->name}->getInputfield($p); $form->append($inputfield); } // add template name field to the form $field = $modules->get("InputfieldHidden"); $field->attr('id', 'Inputfield_template_name'); $field->attr('name', 'template_name'); $field->value = $template; $form->append($field); // append the field // add select_product to the form $field = $modules->get("InputfieldHidden"); $field->attr('id', 'select_product'); $field->attr('name', 'select_product'); $field->value = 1156; $form->append($field); // append the field // add a submit button to the form $submit = $modules->get('InputfieldSubmit'); $submit->name = 'save_new_aanvraag'; $submit->attr("value", "Go"); $form->append($submit); // only show the form if it was not just submitted/processed if (!$input->post->save_new_aanvraag) echo $form->render(); } // process the form if it was submitted if ($input->post->save_new_aanvraag) { // now we assume the form has been submitted. // tell the form to process input from the post vars. $form->processInput($input->post); // validation $email = $form->get("email"); if ($email && (strpos($email->value,'@hotmail') !== FALSE)) { // attach an error and it will get displayed along the field $email->error("Sorry we don't accept hotmail addresses for now."); } // see if any errors occurred if (count( $form->getErrors() )) { // re-render the form, it will include the error messages echo $form->render(); } else { // successful form submission $np = new Page(); // create new page object $np->template = $form->get("template_name")->value; // set template $np->parent = $pages->get('/aanvraag/'); // set the parent $np->of(false); // turn off output formatting before setting values $np->save(); foreach ($np->fields as $f) { $inputval = $form->get($f->name)->value; // sanitize fields if ($f->type == 'FieldtypePageTitle') { $sanitizer->text($inputval); // also set page name based on title $np->set('name', $sanitizer->pageName($inputval)); } if ($f->type == 'Email') $sanitizer->email($inputval); if ($f->type == 'Text') $sanitizer->text($inputval); if ($f->type == 'Textarea') $sanitizer->textarea($inputval); if ($f->type == 'Integer') $inputval = (int) $inputval; // attach fields to page $np->set($f->name, $inputval); } $np->save(); //create the page echo "<p>Page saved.</p>"; } } else { //echo $form->render(); }
    1 point
  27. I think the building of the form the way you are doing should work, and I think it is, correct? But just for something a little cleaner, this is how I always do it: $p = $pages->get($page_id); // make a form $form = $modules->get('InputfieldForm'); $form->method = 'post'; $form->action = './'; $form->attr("id+name",'subscribe-form'); $fields = $p->getInputfields(); foreach($fields as $field){ $form->append($field); } echo $form->render(); Now to the issue of the fields not being added to the new page: It shouldn't matter, but to be more obvious, I would call your new page: $np This should do what you need - you need to iterate through the fields of the new page. $np = new Page(); $np->template = $form->get("template_name")->value; // set template $np->parent = $pages->get('/aanvraag/'); // set the parent $np->of(false); // turn off output formatting before setting values foreach($np->fields as $f) { $np->set($f->name, $form->get($f->name)->value); } $np->save();
    1 point
  28. Just a quick note for future drive-by readers. For some reason $users = wire('pages')->find("template=user,roles=buyer,sort=email"); didn't work for me, but $users = wire('users')->find("template=user,roles=buyer,sort=email"); did. Not sure why.
    1 point
  29. You guys probably already know this, but those permissions assigned at the template level are inherited through the page tree unless you choose "Yes" for defines access in your template settings. Meaning, you only have to define access on templates where you want to change something about the access. For example, lets say you've got a /members/ page that requires a login. You would define access for the template used by the /members/ page. But you wouldn't need to define it on any other templates used on pages below that. Meaning the templates used by /members/cool-stuff/ and /members/great/content/ do not need to define access, because they inherit it from /members/. This is a simple example, but the same rule applies for page editing permissions and such.
    1 point
  30. Permissions aren't a static thing, so I'm reluctant to start adding more static columns of permissions to templates. Permissions are ultimately just pages and any number of unknown permissions can exist. I can't drop permission-to-role assignment because that's the basis of our RBAC, or any RBAC. It would be throwing out the baby with the bathwater. Connecting permissions to the templates (or pages) is just a way of saying where the user can apply a group of permissions that they have. This is an expected part of an RBAC, connecting a group of permissions with another entity for further qualification (whether a page, template or something else). That doesn't mean it's always easy to understand, and RBACs are never straightforward to understand at first glance, but they are powerful. We've attempted to make it more straightforward by separating out a few specific permissions in the template (page-view, page-edit, page-create, page-add) rather than just giving them 1 checkbox that applies all the page-* permissions present in the user's roles (as in most RBACs). But it's a balance of figuring out how far to go with it. If you start taking it to the extreme, then the purpose and power of the RBAC gets lost. Having page-view, page-edit, page-create, page-add in the template access is actually unnecessary for us, but it does reduce the quantity of permissions and roles necessary to achieve a particular access control scenario (which I think is a good thing). However, it's ultimately a tradeoff because it's limiting the power of the RBAC just by having it work that way (like Diogo found). But I think it's a balanced tradeoff because it ultimately reduces complexity, especially for those not familiar with RBACs. Currently, all the page-* permissions except for page-view are activated by page-edit as a kind of a parent permission. So if the user has page-edit, then any other page-* permissions they have get activated along with it. We've separated out page-create and page-add for finer control over those aspects. And we could continue separating out more like you suggested (the ones that are currently parented by page-edit). But I don't want to push further in that direction because I think it's fighting the RBAC and reaching further towards something that can't scale beyond a predefined set of permissions. Adding more columns of permissions in the template only solves it for one person's needs. Eventually WillyC will come along and want to assign page-yoda permission to a template independently of any other permissions. I'd rather go in the opposite direction and reduce what permissions can be assigned at the template (by default), but make it definable. Imagine going to Modules > Process > ProcessTemplate > [edit module settings] and selecting from an asmSelect which permissions should be assignable at the template level -- a nice power user option? That way we aren't presenting a giant table of checkboxes for the vast majority that do not need this, but we are giving the power-user option to those that do. After all, this is the first time I've ever heard of someone wanting to give access to sort children of a page without being able to actually edit the page. So it seems like an unnecessary level of complexity for most to have to consider these rare cases every time they setup template permissions. But if we give the superuser control over what permissions deserve this "assignable at template" status, then I think that lets us veer towards simpler and more powerful at the same time.
    1 point
×
×
  • Create New...