Leaderboard
Popular Content
Showing content with the highest reputation on 04/24/2017 in all areas
-
Can it be done? Absolutely. Is this an ideal first PW project? Hmmm... $64,000 question. It really depends on your level of front end development experience. I don't even say PHP here because you could use almost any front end - I assume nodebb uses node.js and AFAIK there isn't anything to stop you doing that if you really wanted to (but you'd really have to want to) and just use PHP for template files. My thoughts - Front end member registration, password retrieval, etc. Absolutely - simple (and not so simple) forms are easy with just html - no need for the API - just always use sanitizer. (There are a couple of modules for emailing users and forcing new passwords that might help, however.) Front end thread creation by all members (I assume each new thread would be a separate "page") <?php if($user->hasRole('member')){ echo "<form class='createNewThread'>.....</form>"; } You'll need to expand on the <form>, and server side check $user->hasRole() again for security, but that's pretty much all there is to it. Front end member profile editing See my answer re registration. Picture upload required to create each new thread This works lovely with PW (I'm just using it on a project.), for example. Handling the PW side is made much easier by reference to Soma's gist (which has become the de facto method as far as I'm concerned, at least). (Bonus hint - loads of other good stuff there, too.) Picture upload optional on all subsequent comments inside a thread See above. Front end post and comment uploads restricted to images only – .jpg, .gif, .png Because code referred to above uses WireUpload class, that's easy. Appropriate security to prevent uploading malicious files disguised as images See above, but with any security issue, take care. Optional tagging of each thread as it's being created Just search the forum/modules directory. Automatic SEF urls created based on the thread title ( e.g. http://site.com/forum/title-of-my-thread-12345 -or- http://site.com/forum/12345/this-is-title-of-my-thread ) Already built-in, as others have said. Sitewide search feature You'll need to roll your own, but it's not hard. The search page from Ryan's skyscrapers profile is a good source of ideas. I know much of the above duplicates what others have said, but it surely doesn't hurt to have a bit of confirmation.3 points
-
Also, there is more API-styled way to get flat array of id => name $pages->find('id=' . join('|', $userids))->explode("name", ["key" => "id"]);2 points
-
@SamC, I'm using Processwire with INFINITE AJAX SCROLL + semantic-ui. Messaging system is not yet working as I'd like it. I came up with this idea for amigo.today. It's something like tinder, but for social events. User provides age and city name during sign-up, the I'm using Google API to set geolocation based on the city name/street (that can be updated later in profile). There is also age filter (max difference in age), and gender is mixed to not making it dating site. Every event last max for 7 days, after that they vanish. Users can join events, and after that they can review amigo. More recomendations results in bigger green recomendation bar. Leaving opinion without recomendation result in excluding user both ways (they can't see each other events). If there is no events you can always search by tags on the left side (categories) for last active user in that category (created/joined event in that category) and contact that person (and.. messaging system is not yet perfect). Events wall. Event page, host on the left, on the right side participients (1). It looks simple, and works on mobile too.2 points
-
It seems to be wrong as you call wire() in the global namespace, but you must call it in ProcessWire namespace. What you do is calling \wire(), but it must be ProcessWire\wire(), what would be really weird to add it with every call to a PW function (in a PW programm). Best way would be to add the namespace on top of each *.php file in your template system, (template file, view files, snippet files, ...): <?php namespace ProcessWire; Than it should be valid and functional.2 points
-
It's done. I've considered the options and with @LostKobrakai's advice added beforeCmd config option allowing to run specified command after PW installation but before test suite execution. See more https://github.com/uiii/tense#beforecmd. Currently on master branch only.2 points
-
When building selectors, you can combine multiple values by OR (pipe | character). This is a way to say "find me users with id 1 or 2 or 3 ...", and PW should return every user whose id is in that list. Since "id=1|2|3" itself is a selector, yes, you can combine it with other terms as well. array_combine takes in two parameters, first one is for keys, second is values, and creates a new array from those keys and values. So I used it with usernames as keys and ids as values to get [username => userid] type of array. But you can achieve the same result with plain foreach loop as well. Using your sample code you'd use <?php function qa_get_public_from_userids($userids) { // userids is an array of integer ids [13, 456, 74] etc // global $users; // you can use wire() function instead of globals to access PW variables inside functions $userlist = wire()->users->find('id=' . join('|', $userids)); // usernames are stored in 'name' property // Unless you need [fullname => id] array, you should use 'name' // create an array of [username => userid] $nameWithId = []; foreach ($userlist as $u) { $nameWithId[$u->name] = $u->id; } return $nameWithId; } Also the reason you're getting errors from users() function is they're a part of Functions API, which is disabled under a switch.2 points
-
This is untested, but you can use something along the lines of this <?php $userIds = [1, 2, 3]; // list of ids // build a selector like id=1|2|3|4 $userList = users()->find("id=" . join('|', $userIds)); $names = $userList->getProperty('name'); $ids = $userList->getProperty('id'); // create an array of [username => userid] $namesToIds = array_combine($names, $ids); // or use array reduce // you need basic PHP arrays, which you can get with WireArray::getArray() method $namesToIds = array_reduce($userList->getArray(), function ($carry, $user) { // perform some other checks // ... $carry[$user->name] = $user->id; // fill array with name => id pairs return $carry; }, []); // start with an empty array2 points
-
Hi, Similar discussion with some tips and pointers:2 points
-
To show our *.module files with the correct PHP syntax highlighter is now possible on Github. With new repos, you first need to add a .gitattributes file to it. After that you can view *.module files with the PHP syntax highlighter applied: MetadataExif.module So, this doesn't work with already created / comitted repos by simply adding the .gitattributes file. But it will find its way through different caching layers on github if you add it to your repos and further committs to them. (https://github.com/github/linguist/issues/1792#issuecomment-286379822)1 point
-
FacebookEvents ProcessWire module to get Facebook Page Events using the Graph API. Create an app on Facebook developers website You have to create an app to get appId and appSecret. Those keys are required. Go to Facebook Developers and add a new app. Congrats! Now you can copy your Facebook appId and appSecret. Get your Facebook page ID You can either enter your facebook page ID or the facebook page name. If you enter the Facebook page name, this module will get the page ID for you! Call Module $events = $modules->get('FacebookEvents')->getEvents(); Output Events {% for event in events|reverse %} {% if event.start_time|date('U') > date().timestamp %} <div> {% set dts = modules.get('FacebookEvents').getDates(event) %} <a href="https://www.facebook.com/events/{{event.id}}/" title="Facebook">{{dts.dates}}:</a> {{event.name}} <em>{{dts.times}}</em> </div> {% endif %} {% endfor %1 point
-
I dont know how they work internally, whether they depend on each other, but I'd love to be able to test and buy RepeaterMatrix or Multiplier or Table (or any other) module individually. Whole pack of ProFields modules seems awesome to have, however, being able to buy one for ~$30 --instead of all for $130-- sounds much more affordable and this way I could buy the whole pack part by part in several months and wouldn't think twice. But $130 at once, I can't really justify it (and still havent been able to) just as easily with low (to none) disposable student income. Or instead, having sales one - twice a year would be great as well. One advantage of this change would be allowing more people to buy -> support the development & community -> give feedback -> improve these products. This could also potentially pose a disadvantage where requests from people would increase the headache and time required to respond to all these requests, but this community is more than able to handle that. I'm sure there's a reason to why these modules are sold together, and I'd love to hear your side as well, @ryan, (and all other maintainers). Regards, Abdus.1 point
-
I like the idea of a periodic sale of various products. Also, Have a quarterly or semi-annual contest open to all community non-staff members to develop the best ProcessWire widget. The winner gets the designated product license, second place gets the "All I Got Was This ProcessWire T-shirt". Seriously. Having the ProcessWire logo on items would be great. I'd buy the coffee mug now.1 point
-
Thanks Zeka! This works: function qa_get_public_from_userids($userids) { global $users; $useridtopublic = $users->find('id=' . join('|', $userids))->explode('fullname', ["key" => "id"]); return $useridtopublic; }1 point
-
Do you have namespace <?php namespace ProcessWire; declared on top of your files? What shows up when you var_dump($userlist) inside the function?1 point
-
Great additions, @tpr !! The translation workaround can be also useful when you're creating a site that initially isn't multilanguage, but will be in the future, so you can add the translations strings even if the backend doesn't have the multilanguage modules setup yet.1 point
-
I came up with this idea for amigo.today. It's something like tinder, but for social events. User provides age and city name during sign-up, the I'm using Google API to set geolocation based on the city name/street (that can be updated later in profile). There is also age filter (max difference in age), and gender is mixed to not making it dating site. Every event last max for 7 days, after that they vanish. Users can join events, and after that they can review amigo. More recomendations results in bigger green recomendation bar. Leaving opinion without recomendation result in excluding user both ways (they can't see each other events). If there is no events you can always search by tags on the left side (categories) for last active user in that category (created/joined event in that category) and contact that person (and.. messaging system is not yet perfect). Events wall. Event page. It's not yet ready. I'm not skilled enough to finish this. I'd be happy if someone would like to join this project. Thanks!1 point
-
Hi @Publisher-in-Chief, Welcome to the forums! The link @abdus posted contains an example usage which displays the contents of an rss feed. Copy that example into your template file. Replace the example URL with the one you want to use. View the page. Additional information on usage can be found under the More Details section of that post. Let us know if you need help with what you want to accomplish.1 point
-
Hi @Tyssen, Thanks for your interest in Media Manager. No, not at the moment. The module creates its own fields for the 4 media types (audio, document, image and media). Each media item is a hidden page in the admin under respective media manager parent pages. I have been mulling adding this type of scanning functionality but haven't made a decision yet. Having said that, the module can currently scan /site/assets/MediaManager/uploads/ Please let me know if I can be of further help.1 point
-
Thank You horst, it works! Until now I'm not so familiar with namespaces - the man grows with its tasks...1 point
-
Since the module hooks into Pages::saveReady and Pages::saveFieldReady, it should be called whenever $somePage->save() function is called and a change to DB is necessary.1 point
-
Tense Tense (Test ENvironment Setup & Execution) is a command-line tool to easily run tests agains multiple versions of ProcessWire CMF. Are you building a module, or a template and you need to make sure it works in all supported ProcessWire versions? Then Tense is exactly what you need. Write the tests in any testing framework, tell Tense which ProcessWire versions you are interested in and it will do the rest for you. See example or see usage in a real project. How to use? 1. Install it: composer global require uiii/tense 2. Create tense.yml config: tense init 3. Run it: tense run For detailed instructions see Github page: https://github.com/uiii/tense This is made possible thanks to the great wireshell tool by @justb3a, @marcus and others. What do you think about it? Do you find it useful? Do you have some idea? Did you find some bug? Tell me you opinion. Write it here or in the issue tracker.1 point
-
Thank you. I really appreciate the link and the code being on github. I learn a lot by reading code and yours is very helpful. I've solved the problem for one template but your solution is more general so when the inevitable additional template comes along, I'll most likely move to your module. Thanks for putting it together and pointing me at it.1 point
-
My module (https://processwire.com/talk/topic/9496-restrict-tab-view/) mentioned above still works fine in PW 3 if that's helpful for you.1 point
-
Process modules (ones that extend Process class) can have execute[Action] methods that are called with their respective urlSegments. In case of your example, the method comments portrait the exact conditions where ___executeFields is executed with /fields urlSegment, for instance. The problem with this approach is that you cannot (or should not) use them on frontend, as Process modules are intended for backend use (unless I'm mistaken). However, calling the method depending on urlSegment is quite simple with the snippet I posted earlier. You can use something similar to following to call execute[Action] methods <?php public function ready() { // accept only single urlSegment if($this->input->urlSegment2) throw new Wire404Error(); // always sanitize user input $method = $this->sanitizer->alpha($this->input->urlSegment1); if(!$method) return; // or perform more sophisticated checks // respond to execute[Action] methods // such as executeList() with /list urlSegment // or executeFields() for /fields urlSegment // create camelCase method name // /json urlSegment will be intercepted by executeJson() function $method = "execute" . ucfirst($method); if (method_exists($this, $method)) { $this->{$method}($param1, $param2); } else { // method does not exist throw new Wire404Exception(); } } public function executeJson() { echo json_encode(['a' => 1, 'b' => 2]); } Put this inside your init() or ready() method in your module to relay the request to specific functions.1 point
-
Hi, It can definitely be crafted with ProcessWire, but your requirements are a bit tough for a starter, I guess. Anyway, if you have the time and take the challenge, I would start by taking a look at this: As far as I know most of its UI features are implemented for the admin area, but it is possible to "let regular members" work in the admin, rather than implementing "custom frontend" interface for them. Lots of PW developers opted for this path already. I recommend searching the forum for more info, like: https://www.google.hu/search?as_sitesearch=processwire.com%2Ftalk&as_q=migrate#q=form+api+site:processwire.com/talk One more tip: ImageMagick. You will probably need a server with this as GD chokes on big files.1 point
-
1 point
-
Guys, if you have a lot of time to spare, you can kill some by checking out this list: https://github.com/neiesc/ListOfMinimalistFrameworks1 point
-
Hi, version 1.0.0 is released. The main changes are: project's name is changed to Tense (Test ENvironment Setup & Execution) Symfony/Console is used for colored output and arguments parsing config file uses YAML instead of JSON tense init command can be used for config file initialization waitAfterTests option renamed to pause1 point
-
Just upgraded the module to v0.4.3. There's a new option to disable the "noescape" filter, and a workaround for translations on a non-multilanguage site. The latter is a simple solution for a situation when you copy over a latte file from another project full with translations but the current project is single-language only. This is perhaps not an issue if you're using full strings for translation keys, e.g "_t('Read more')" instead "_t('read_more_text')" because the original key is returned. But even so you may start a non-English project and there you'll be in trouble I was there several times and ended up rewriting strings/translations all over the project, now they can remain in place and I have to add translations at one file (which you can copy over).1 point
-
Actually, Ryan has not yet released an updated "official" and installable version of this profile, so currently the easiest one to install should be the one I linked to.1 point
-
@Neveroff Hi, I've not yet tried to install it but you might want to give a try to this one instead: https://github.com/dadish/pw-skyscrapers-profile Introduced in this video:1 point
-
@Richard Jedlička A single like is not enough! This is a long-overdue and needed tool - thanks for contributing it. Personally, I think WireTest is a fine name for this.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
-
Well, thanks for the props but that might not be the case. A better solution to the problem might be found in either removing the hard-coded label set from the ___render() routine or in doing what PW does for its own admin login: use an InputfieldText rather than an InputfieldPassword! Here it is straight from ProcessLogin.module... $this->passField = $this->modules->get('InputfieldText'); $this->passField->set('label', $this->_('Password')); // Login form: password field label $this->passField->attr('id+name', 'login_pass'); $this->passField->attr('type', 'password'); $this->passField->attr('class', $this->className() . 'Pass'); First time I've noticed that the login page isn't using InputfieldPassword. Any mileage in that approach for you Gerhard?1 point
-
For any PageArray, count($pageArray) returns the number if items present now, but $pageArray->getTotal() returns the number of items total without pagination. So if you specified a "limit=n" in your selector when loading the pages, you can always call upon that $pages->getTotal() to tell you how many matched in total. There is also a $pageArray->getStart() method, which tells you the index of the first item. So if you had specified "limit=10" and you were on page2 in the pagination, then getStart() would return 10. I use these two functions to output a summary of results that tells you were you are. So if you wanted a headline that said this: You'd do something like this: $firms = $pages->find('parent=/firms/, num_staff>100, limit=10'); $start = $firms->getStart() + 1; $end = $firms->getStart() + count($firms); $total = $firms->getTotal(); echo "<h1>Firms with more than 100 staff</h1>"; echo "<h2>Showing firms $start - $end of $total</h2>"; foreach($firms as $firm) { echo "<p>{$firm->title} has {$firm->num_staff} staff</p>"; } // output the pagination links echo $firms->renderPager();1 point