Leaderboard
Popular Content
Showing content with the highest reputation on 03/22/2016 in all areas
-
...and you tell him, that you will do the backend with processwire, what comes out is this: http://kreativan.net/blog/news/website-relaunch/11 points
-
Spent about an hour to find a flexbox grid that utilizes sass and doesn't require adding classes to markup. Finally I found this: https://ajy.co/the-simplest-sass-flexbox-grid-ever Keeper!5 points
-
3 points
-
This is only true if language of current user (set in backend) is default. // define language var before login take current language of page $language = $user->language // redirect to this language after login $session->redirect($pages->get("template=home")->localUrl($language)); Small hints 1) Read the docs https://processwire.com/api/multi-language-support/multi-language-urls/ 2) use http://example.org/jpn/login instead of http://mydomain.com/jpn/login3 points
-
MySQL (InnoDB) only very recently got the ability to allow index searches with bitwise operations. With the current (5.7.8) release, you can add a generated or virtual column to the pages table and index that. If the column operation in the query matches the column definition, the index is used. This should look something like the following (untested): ALTER TABLE pages ADD stpublished INT AS (status & 2048) STORED; CREATE INDEX idxstpublished ON pages (stpublished); After that, any queries with matching conditions like "pages.status & 2048 = 2048" or "pages.status & 2048 > 0" should hit the index. That's still a bit bleeding edge, but since Oracle officially promotes this feature (it's a must-have for the also advertised JSON column type to be of use), it should be reasonably stable by now. Of course, you have to have a generated column for every comparison you want to speed up, and having one adds another little performance penalty on insert operations.2 points
-
2 points
-
just had to do a simple 1-level menu on my new website and was once again surprised how easy things can be with the great API. i was doing navigations like in the examples above but today i took a slightly different approach that in my opinion is a little bit better to read and maybe easyer/cleaner to understand: function renderMenu($page) { // get the root page $hp = wire('pages')->get('/'); // set pages that should have "active" class // remove root page otherwise this would always be active // if current page == rootpage it will be appended and set active $active = $page->parents ->remove($hp) ->append($page); // set pages that should be shown in the menu // easy in this case because it is only 1-level $menuitems = $hp->children ->prepend($hp); // return the markup $out = ''; foreach($menuitems as $item) { $cls = ($active->has($item)) ? ' class="uk-active"' : ''; $out .= '<li' . $cls . '><a href="' . $item->url . '">' . $item->title . '</a></li>'; } return $out; } or with less comments and most on one line: function renderMenu($page) { $hp = wire('pages')->get('/'); $active = $page->parents->remove($hp)->append($page); $menuitems = $hp->children->prepend($hp); $out = ''; foreach($menuitems as $item) { $cls = ($active->has($item)) ? ' class="uk-active"' : ''; $out .= '<li' . $cls . '><a href="' . $item->url . '">' . $item->title . '</a></li>'; } return $out; } of course that is really a little difference to the examples above, but sometimes for me it got a little confusing to handle the "active" class with some IFs and ORs and ANDs and the approach with prepend() append() add() or remove() may be more elegant. another thread for reference if anybody is having trouble https://processwire.com/talk/topic/288-solved-navigation-current/2 points
-
If you're using the api in classes or functions these variables are not available as such. You'd need to use $this->wire('pages') or wire('pages') depending on the current scope.2 points
-
2 points
-
After i learned a few things about php, i believe that i can port the plugin. But for that I need some help with the integration of functions. For the Plugin i need to save the IP (in shorted form) within the Comment. For this reason I have to expand to an IP field the comment database. All the filters are Optional: Check the comment IP with approved comments in the database Match the comment IP with external spam Database trust comments with gravatar classify BBCode as spam use regular expression create and use a local spam database At the moment i create the functions for doing the stuff in the list above. The next step is to integreat the Plugin to the processwire System and at least i will add support to limit comments to defined language. For all who interested at this plugin can follow on the Github project: https://github.com/kreativmonkey/antispam-guard2 points
-
No you use $pages->find("template=basic-page, status=unpublished"); Respectively $pages->find("template=basic-page, status=published"); But since $pages->find("template=basic-page"); returns only published pages anyway that are not hidden and above, a status=published makes no sense.2 points
-
That's the sanitizer (filename) at work. From PW's point of view, it doesn't matter. It will get the correct file (it has been renamed). So the question really should be, does it matter on your side? E.g. Do you have another API outside PW or another APP that will expect your image files named using a particular format? If the answer is no, then it doesn't matter. If yes, I think Adrian has a file renamer module that can be configured to your heart's desire.2 points
-
Srcset and picturefill or if it needs to be super simple just a 2x low-quality image.2 points
-
$largePargeArray->removeItems($subsetPageArray); should work as PageArray inherits from WireArray.2 points
-
Support thread for WireMail Mailgun. For bug reports, please use the bug tracker on GitHub. https://github.com/plauclair/WireMailMailgun1 point
-
In the last few weeks I've notices some request (e.g. here and here) to be able to get pages based on if they are selected in page fields of other pages. I think adding a method for this would be a nice addition to ProcessWire, as it's often the case that the pages itself are options we just want to get, if they are used somewhere. Currently the task "Get all tags used by some blogposts" has to be done manually like this: $tags = $pages->find("template=tags"); foreach($tags as $tag){ // Filter unavailable if(! $pages->count("template=posts, tags=$tag") ) continue; // Do stuff with it } Now it would be nice to have something like this, where we don't need to have a selector for tags (this is done by the pagefield already). // Find all pages, which are selected in the "tags" field of the selected posts $available_tags = $pages->findSelectedPages("template=posts", "tags"); I'm not that big a MySQL guy, but I can imagine this not only improving readability, but also reducing database calls.1 point
-
This tutorial will outline how to create a membership system that requires account activation via email. If you have a decent understanding of ProcessWire it isn't difficult at all! Create additional fields By default ProcessWire has a name, email, and password field for the user template. To allow for account activation we will have to add a couple more fields. Create the following fields and add them to the systems default user template. You can make ProcessWire show the system templates by going to setup -> templates -> toggle the filter tab -> show system templates -> yes. user_real_name user_activation Okay great, now that you have added the two additional fields to the user template we can start to code the registration form. I am not going to spend a lot of time on this part, because there is a tutorial that describes creating forms via the API. Create the registration form Once you have followed the tutorial on creating forms, you will have to add a couple of sections to your new form! <?php include("./functions.php"); require("/phpmailer/class.phpmailer.php"); $out = ""; $errors = ""; //create form //full name field //email field //username field //password field //submit button //form submitted if($input->post->submit) { $form->processInput($input->post); //instantiate variables taking in the form data $full_name = $form->get("full-name")->value; .... /* * Create the activation code * You can add a random string onto the * the username variable to keep people * from cracking the hash * ex $activation = md5($username."processwire"); */ $activation = md5($username); $activation_code = $config->httpHost."/activation/?user=".$username."&hash=".$activation; //check for errors if($form->getErrors() || username_validation($username) == 0) { $out .= $form->render(); //process errors /* * this checks to makesure that no one has the username * I have a functions file that I import to the pages I * need it on */ if(strlen($username) != 0){ if(username_validation($username) == 0) { $username->error = " "; $errors .= "Sorry that username is already taken!"; } } } //the registration was successful else { $out = "Thank you for registering!<br><br>"; $out .= "An email has just been sent to " . $email . " with the url to activate your account"; /* * In this example I am using phpmailer to send the email * I prefer this, but you can also use the mail() function */ $mail = new PHPMailer(); $mail->IsHTML(true); $mail->From = "email@domain.com"; $mail->FromName = "Register @ Your Site"; $mail->AddAddress($email); $mail->AddReplyTo("email@domain.com","Register @ Your Site"); $mail->Subject = "Registration"; $mail->Body = " Hi " . $full_name. ", <br>" . "Thanks for registering at Your Site. To activate your email address click the link below! <br><br>" . "Activation Link: <a href='http://".$activation_code."'>".$activation_code."</a>"; $mail->send(); //create the new user $new_user = new User(); $new_user->of(false); $new_user->name = $username; $new_user->email = $email; $new_user->pass = $password; $new_user->addRole("guest"); $new_user->user_full_name = $full_name; $new_user->user_activation = $activation; $new_user->save(); $new_user->of(true); } } //form not submitted else { $out .= $form->render(); } ?> <h2>REGISTER</h2> <div class="errors"><?php echo $errors; ?></div> <?php echo $out; ?> Okay so that outlines the entire form. Let me get into the important parts. Checking for a unique username /* * check if username exists * return 1 username is valid * return 0 username is taken */ function username_validation($username) { $valid = 1; $check = wire("users")->get($username); if ($check->id) { $valid = 0; } return $valid; } We don't want to try and add a username if the username is already taken, so we need to make sure to validate it. If this returns 0 you should output that the username is already taken, and the user needs to choose a different one. Generating an activation code /* * Create the activation code */ $activation = md5($username); $activation_code = $config->httpHost."/activation/?user=".$username."&hash=".$activation; This generates an activation code. It does so by encrypting the username variable and then combines the username and activation code into a url for a user to visit. Now we have to process the activation code. As the teppo recommended, it is a good idea to add an extra string onto the $username when encrypting it with md5. If you don't do this, people may crack it and allow for mass signups. $activation = md5($username."Cech4tHe"); Activate the user <?php include("./head.inc"); include("./functions.php"); /* * this will pull the username and * activation code from the url * it is extremely important to * clean the string */ $activate_username = $sanitizer->text($_GET['user']); $activate_hash = $sanitizer->text($_GET['hash']); if(wire("users")->get($activate_username)->id) { if(strcmp(wire("users")->get($activate_username)->user_activation, $activate_hash) == 0 || wire("users")->get($activate_username)->user_activation == 0) { echo "Your account has been activated!<br><br>"; $activate_user = wire("users")->get($activate_username); $activate_user->of(false); $activate_user->user_activation = "0"; $activate_user->save(); } else { echo "There was an error activating your account! Please contact us!<br><br>"; } } else { echo "Sorry, but that we couldn't find your account in our database!<br><br>"; } include("./foot.inc"); This pulls the username and activation hash from the url. It then goes into the database and looks for the user. Once it finds the user, it get's the user_activation hash and compares it to the one in the URL. If it matches, it activates the user by setting user_activation to zero. Clean the url You can user the built in $sanitizer->text() method to clean the url. This will keep people from inserting special characters that can break the page. Keeping unactivated users out You aren't done yet! Now you will have to choose which areas you want to restrict to activated users only. An activated user's user_activation field will now equal zero. So if you want to restrict a section check to make sure it is zero...... if($user->user_activation != 0) { echo "Sorry, but you need to activate your account!"; } else { // activated users }1 point
-
If you don't want to use the template compiler, all you need to do is to add the ProcessWire namespace on top of your template file: <?php namespace ProcessWire; Here you can find the blog post about this topic.1 point
-
That's a fact that nobody can rely on, therefore it's not present in the processwire selector api. You could however do in with raw mysql or in memory with php.1 point
-
If you haven't, you can read a bit in the docs here: https://processwire.com/api/modules/ Depending on what your module / class has extended, you may also use $this->pages->find() And if you use procedural functions, you can use function myFunction() { $pages = wire('pages'); $pages->find(); ...1 point
-
The sort selector does only fallback to the second parameter for items, where the first sort parameter is the same value. It's not combining both field values to sort afterwards – they might even be not comparable because of different types.1 point
-
1 point
-
It could be as simple as having code like this in your RuntimeMarkup field settings for template 1 //pseudo code $out = 'No value entered'; if($page->name_of_single_page_field->title == 'whatever') { $out = $pages->get('/some-page/, template=template-2')->title; } return $out; If you have further questions let's take it at the module's support forum1 point
-
No, PW doesn't have to go through all pages, it's DB query. Field "published" is brand new and for timestamp of the publish date. If a page is published or not is in status and it's a bitmask.1 point
-
Hello, module uses the PW form api and isn't styled: https://processwire.com/talk/topic/2089-create-simple-forms-using-api/ https://processwire.com/talk/topic/6184-form-and-css/ Just overwrite the (emtpy) style and script files Link to the documentation: Styles, scripts & templates The error message is defined by the form api / inputfield. You can overwrite it too. https://processwire.com/talk/topic/4659-customizing-error-messages-for-inputfields/ Regards1 point
-
I seem to recall something similar but can't find it now. You could consider using the module RuntimeMarkup using some custom JS to monitor select changes or if you don't want it to detect live changes just to display the output you want on save. Your PHP code could even reside in a file that you could access using WireRender(). It (the output) wouldn't really be 'adjacent' to your Page Field though1 point
-
You can hook ProcessPageEdit::buildForm to dynamically add custom fields (e.g. InputfieldMarkup) to page edit forms based. Is that what you're looking for?1 point
-
https://processwire.com/talk/topic/9730-get-pages-used-by-a-pagefield/1 point
-
Yes, a plain textarea works best for this. I use the same technique in Menu Builder. Form Builder also stores data as JSON. Same as @tpr, the main disadvantage I see is searching. What's you rationale for 1 page per poll? Why not 1 page per question? With the former, it is a bit difficult to compare how a specific question was answered. I guess it all depends on what you want to do with the survey afterwards. I don't understand this. What are these child pages? What is their parent page? At the end of the day, it really depends on 1) scalability 2) what you are after. Are the individual users the main object of your study? i.e. are you mainly interested in what 'John' said as compared to 'Mary'? Or, are the questions themselves the most important thing, e.g. 'Drink A tests better than drink B', 'Car X is better than can Y'. Easier approach is not always best approach. When it comes to analysing your data you want that to be as most efficient as possible. It might not have been 'easier' to set up, but it will provide a more meaningful insight into the data (plus maybe easier to maintain) than the 'easier' way . I guess what I am saying is that it's hard to give a definitive answer because it's not clear what you want to do with the data in the end (and also how you want it maintained). The answer to that/these question(s) might mean it is better to use pages instead; or it is better to use JSON or even custom SQL tables. Just my 2p1 point
-
I haven't tested the new matrix field for now. PTE renders the selected templates/blocks for the editor. So the dev could create a simple visual blockeditor with drag and drop the blocks and prerender them like it looks on frontend or in a other way that fits in the backend like teammembers, slideimages and so on. Some things to mention: - Care for the used templates to render in SEO things - access the single parts are possible if you don't handle this (for example you have all PTE elements under a hidden parent the elements are accessable on frontend, too) - The CSS for prerendering is sometimes a little tricky since it could be that it crashes with the admin styles (only some special classes and maybe fontsizes and so on) you could use .renderedLayout Class on such elements in your special CSS file for PTE. I'm running PTE for pretty much every repeating element that is more complex like contentblocks, sliderimages with text and settings, teammembers, grouping documents and so on...all things that elements in summary are under a rage from 10 to maximum 40. If i need more elements like events or something i'll stick to pages. best regards mr-fan1 point
-
For JSON storage I'm using a render and renderValue hook that turns a textarea to formatted table layout in my form submissions: It works quite well, the only disadvantage is that you can't search entries like 'email=...' because there are only 1 field (json_storage). But I guess you don't need this feature anyway. I can share the code if you wish, though it's part of a module so it's not that easy to decouple.1 point
-
This looks like wd_shared_image is set to hold multiple images, so $p->wd_shared_image stringifies to a list of all of its childrens' image names but only url and path hold a sensible value as $p->wd_shared_image returns a PageImages instance.1 point
-
I recommend using kongondo's ApiGen Docs, for example 3.x: http://kongondo.github.io/ProcessWireAPIGen/devns/class-PageArray.html Ryan's doc pages should be considered "for introduction purposes only". We cannot expect him to keep it up-to-date1 point
-
This is sweet. And sooo easy to add to any PW site. http://blog.watchandcode.com/2016/03/17/the-single-piece-of-javascript-on-hacker-news/1 point
-
My current grid system is this, based on inuit.css's layout object: Include the mixins and some media queries (99% only for updating the width) and most grids are done.1 point
-
I added an option to disable multi-language fields. In field settings for Image Extra Fields there is a new checkbox "Disable multi-language fields?". Please pull branch develop to get this new feature. btw: branch develop is ProcessWire 3.x ready but it needs a bit more testing before I'll create a new release.1 point
-
Yeah, it is probably pretty niche, but it can be very handy if you want to implement something like OAuth or OpenID without all the heavy lifting those entail. My immediate use case is that it's easier for me to log in to my site on mobile by just entering my domain now. On http://indiewebcamp.com it's used as the authentication mechanism for the wiki. It's worked great there to prevent spam accounts/wiki edits.1 point
-
Hi guys, I'm trying to integrate the facebook sdk to register/login users but I'm getting a strange error when I try to create a new user after I get the facebook token. Fatal error: Class 'User' not found in /var/www/vhosts/httpdocs/site/templates/social_fb_callback.php on line 41 it's possible the facebook sdk interferes with pw classes? this is the complete code. I'm on PW 3.0.10 <?php require_once('../Facebook/autoload.php'); $fb = new Facebook\Facebook([ 'app_id' => 'xxxxx', 'app_secret' => 'xxxxx', 'default_graph_version' => 'v2.5', ]); $helper = $fb->getRedirectLoginHelper(); try { $accessToken = $helper->getAccessToken(); } catch(Facebook\Exceptions\FacebookResponseException $e) { // When Graph returns an error echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(Facebook\Exceptions\FacebookSDKException $e) { // When validation fails or other local issues echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } if (isset($accessToken)) { // Logged in! $session->facebook_access_token = (string) $accessToken; // OAuth 2.0 client handler $oAuth2Client = $fb->getOAuth2Client(); // Exchanges a short-lived access token for a long-lived one $longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($session->facebook_access_token); $token_fb = $sanitizer->selectorValue($session->facebook_access_token); $checkUser = $users->get("token_fb=$token_fb"); if($checkUser instanceof NullPage){ // new user try { $fb->setDefaultAccessToken($session->facebook_access_token); $res = $fb->get('/me?fields=first_name,last_name,email'); $userNode = $res->getGraphObject(); // get profile picture $res = $fb->get( '/me/picture?type=large&redirect=false'); $picture = $res->getGraphObject(); // get email if($userNode->getProperty( 'email' ) == ''){ $uemail = "tocomplete"; }else{ $uemail = ""; } $nome = $userNode->getProperty( 'first_name' ); $cognome = $userNode->getProperty( 'last_name' ); $pass = "vogliadi".rand(100,10000); // creo username dal nome e cognome e se esiste aggiungo un numero alla fine. $username = strtolower($nome).strtolower($cognome); $checkuser = $users->get("name=$username,token_fb!=$session->facebook_access_token"); if($checkuser->id){ $username = $username.rand(10,100); } //registro utente $u = new User(); $u->name = $username; $u->pass = $pass; $u->passclear = $pass; $u->email = $uemail; $u->nome = $nome; $u->cognome = $cognome; $u->token_fb = $session->facebook_access_token; $u->privacy_newsletter = 1; $u->addRole("guest"); $u->addRole("member"); if($u->save()){ $u->profilepic = $picture['url']; $u->save(); $session->login($u->name,$u->pass); } $session->redirect("/",false); } catch(Facebook\Exceptions\FacebookResponseException $e) { // When Graph returns an error echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(Facebook\Exceptions\FacebookSDKException $e) { // When validation fails or other local issues echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } }else{ // login $session->login($checkUser->name,$checkUser->password); $session->redirect("/",false); } }1 point
-
1 point
-
I don't share the warm fuzzy feelings I get when I use people's modules nearly often enough, so I just left a comment on the module directory page. The short version is that it's saving me from having to create custom modules for a lot of places where I'd want to output some custom, processed output when editing a page and it is streamlining some of the steps I need to perform when approving entries in the dev directory, so thanks for this!1 point
-
How about such a syntax? I think this would be flexible enough for any kind of tagging structure. // Get me the tags, // which start with "Tech_", // are used in the tags field of "templates=posts, date>today" // and sort them by number of occurences (maybe named count) $pages->find("template=tag, title^=Tech_, in.tags=[templates=posts, date>today], sort=occurences"); // Not limiting to upcoming posts or even posts $pages->find("template=tag, title^=Tech_, in.tags=[*], sort=occurences");1 point
-
Update: version 0.0.2 As requested by @Macrura, added a markupValue() method to correctly output the field's markup output in listers.1 point
-
Greatly useful module guys, thanks! Just used it to provide a list of collected emails for simple copy/paste into send field return $page->children->implode(', ', 'email'); Couldn't get any simpler than this! PS: of course it would be great to have ACE on the code field like i Hanna Code1 point
-
1 point
-
I fixed the issue referred to in Nik's GitHub issue report (thanks Nik). As for sorting the items in the repeater, I think the situation you are trying to accommodate here is a little unusual. Wouldn't the date field be associated with the 'event' rather than for some repeatable field within the repeater? It can't sort on eventdetails.date because it's not referring to any single date, but rather any number of potential dates. What I'd suggest is adding an 'date' field to your 'event' template that represents the event starting date. But if you want it to work with what you've already got, then I suppose you could query the repeaters rather than the events (though I've not yet tried this): $events = new PageArray(); $items = $pages->find("template=repeater_eventdetails, date>0, sort=date, include=all"); foreach($items as $item) { $event = $item->getForPage(); if($item->isPublic() && !$events->has($event)) $events->add($event); }1 point
-
1 point
-
It's one of the statuses you see in the top of the Pages class. So you can set the status using it like: $page->status = Page::statusUnpublished; Edit: Have you looked on the Cheatsheet? For reference under "Page Status" http://processwire.com/api/cheatsheet/ BTW aren't you the guy with the processwiresexy, whatever? I'm kinda surprised you didn't know this.1 point