Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 11/02/2016 in all areas

  1. you could also try using a token like {{column-break}} and then use this function on your body field output: function columnizeMarkup($markup) { if(strpos($markup, '<p>{{column-break}}</p>') == false) return $markup; $bodyParts = explode('<p>{{column-break}}</p>', $markup); $colClass = 12 / count($bodyParts); $columns = ''; foreach($bodyParts as $col) { $columns .= "<div class='col-md-{$colClass}'>$col</div>"; } return '<div class="row">' . $columns . '</div>'; }
    8 points
  2. Sundaraijal Children's Home [s4ch.org] is a small project founded by a wonderful guy named Ram, whom I've met during my stay near the roof of the world. Abandoned, addicted to glue kids are being given a second chance. www.s4ch.org Used modules: CroppableImage AIOM Markup Sitemap XML Page Rename Custom Upload Names Google Analytics RandomImages There are still some minor issues to resolve, but mainly it works... Most content is being added by David [a Spanish volunteer]. Ideas and/or improvements are always welcome!
    6 points
  3. I recommend using API $variables for most cases, but here are a few instances where you may prefer the function versions: If an API variable is out of scope (like in a function), then you may find the new function versions very useful. If your editing environment provides more benefits to you for using the function versions (like auto-completion and docs) then that's also a compelling reason to use them too. This is something we haven't been able to provide before now. If both of the above apply to you, then also use the functions API where you would have previously used wire(). If neither of the above apply to you, then just use API $variables (fewer characters to type, and no questions about what instance). Basically, use whatever provides the most benefits to your scenario. For all practical purposes, $page and page() are synonymous. I don't see any reason to use $wire in template files–that's really more for core use. The new skyscrapers template files were specifically developed to demonstrate the API variables as functions for that blog post. Basically, I wanted to show you how they work rather than just telling you. So I went out of my way to use them for this particular case. I personally use API variables in my sites, though will be glad to have the convenience of more options when needed. Function alternates to our API variables have been requested multiple times. That's because it's more friendly in how it enables communication between developer and editing environment. I agree that's a good reason to have them. However, you'll likely only want to use them if you find them beneficial in this way. It's completely IDE friendly, and that's actually one of the reasons for this approach versus using user defined $variables for regions. We're just working with strings here. Keep in mind the "+" is only something you add to the region name if you specifically want to prepend or append to an existing value that's already present in there… and most usages probably won't involve that. I'm not sure how to make prepending or appending more convenient than adding a single "+" character to the region name. I'm lazy and don't like to type a lot, so gravitate towards the simplest possible solution. But always open to suggestions.
    5 points
  4. just because i needed this again today: if you are dealing with any sort of tags (HTML data) in your fields, than the easiest solution is to base64_encode($var) your data in the export and then base64_decode($var) it in your import. i had to import some pages with inline images today and if you know how to do it, that is also quite easy and straigtforward. the problem is, that you have some html like img src="/site/assets/files/12345/your-image.jpg" in your field and the ID will change after the import! sample export xml - note the tag <pid> holding the old id echo "<?xml version='1.0' ?>"; echo '<pages>'; // find pages $results = $pages->find('parent=/your-parent/'); $results->add($pages->find('parent=/something-else/')); foreach($results as $p): $p->of(false); ?> <page> <title><?= $p->get('headline|title') ?></title> <date><?= $p->created ?></date> <featured>1</featured> <pid><?= $p->id ?></pid> <pic><?= $p->coverpic->first()->httpUrl ?: '' ?></pic> <body><?= base64_encode($p->body) ?></body> <images><?php foreach($p->images as $image) { echo '<image>' . $image->httpUrl . '</image>'; } ?></images> <files><?php foreach($p->attachments as $file) { echo '<file>' . $file->httpUrl . '</file>'; } ?></files> <gallery><?php foreach($p->gallery as $image) { echo '<image>' . $image->httpUrl . '</image>'; } ?></gallery> </page> <?php endforeach; echo '</pages>'; die(); and then the import: $items = simplexml_load_file('your-url-of-export-data'); foreach($items as $page) { $p = new Page(); $p->template = 'blogitem'; $p->parent = '/news'; $p->title = $page->title; $p->name = $sanitizer->pageName($page->title, true); while($pages->find('parent='.$p->parent.',name='.$p->name)->count() > 0) $p->name .= '-'; $p->date = $page->date; $p->featured = $page->featured; // get body html and remove root node $p->body = base64_decode($page->body); $p->save(); // change images in body field $re = '/src="\/site\/assets\/files\/' . $page->pid . '\//'; $p->body = preg_replace($re, 'src="/site/assets/files/' . $p->id . '/', $p->body); $p->save(); // add images if(strlen($page->pic)) $p->pic->add((string)$page->pic); foreach($page->images->image as $image) $p->images->add((string)$image); foreach($page->files->file as $file) $p->files->add((string)$file); foreach($page->gallery->image as $image) $p->gallery->add((string)$image); $p->save(); echo 'new page <a href="' . $p->editUrl . '" target="_blank">' . $p->path . '</a><br>'; } die(); just set your ckeditor field settings porperly before your import and all images will be recreated on your new site! remark: this will only replace images from the same page and not any images that are linked from a different page with different page-id. that would need some extra mapping of old-id --> new-id
    4 points
  5. Could be you need to increase post_max_size
    3 points
  6. @adrianmak I would strongly consider you don't put divs in CKeditor fields as this is a very fragile and error-prone approach. My solution to this is either (a) use HannaCodes to represent opening and closing of divs or (b) use RepeaterMatrix.
    3 points
  7. @Macrura That's quite nice, could make a useful textformatter.
    3 points
  8. THIS MODULE IS AWESOME! just to say it....
    3 points
  9. My suggestion $temp = $pages->find('template=trip, tripdata_category='.$page); $trips = new PageArray(); foreach($temp as $tp) { if($tp->tripdata_category->first() == $page) $trips->add($tp); }
    3 points
  10. i think that woulb be totally enough and if that is simpler, i would be totally happy with that you brought up a new idea: what if the code restore feature that you implemented remembered the window/tab somehow? do you think that would be possible? i guess a simple solution would be to store it based on the url path in a cookie. another idea, and a short explanation why i think that this would be useful: in the last weeks i found myself often do something like this: $m = $modules->get('mymodule'); $m->upgrade(1,2); // test upgrade from version 1 to 2 $m->upgrade(2,1); // test downgrad from version 2 to 1 i then have to (un)comment one of those lines repeatedly... i think a history would be quite nice! simpler and maybe easier and more efficient than a snippet library (or similar in many cases): just put a comment in the first line and it would save it to the history. what do you think?
    2 points
  11. this is another solution i used lately: javascript for handling the clicks: // mobile menu click handler $('#tm-mobile-nav').on('click', 'a,i', function() { // if the link icon was clicked go to url if($(this).is('i')) { location.href = $(this).data('mobile-link'); $(this).removeClass('uk-icon-arrow-right').addClass('uk-icon-spinner uk-icon-spin'); } }); css for handling the visibility: /* mobile menu */ #tm-mobile-nav li .uk-icon-arrow-right { display: none; } #tm-mobile-nav li.uk-parent.uk-open .uk-icon-arrow-right, #tm-mobile-nav li.uk-parent .uk-icon-spinner { display: inline-block; margin-left: 10px; } and php (using custom UIKIT markup): $out .= "<li class=\"{$cls}\"><a href=\"" . ($item->numDropdownItems ? '#' : $item->url) . "\">{$item->title} <i data-mobile-link=\"{$item->url}\" class=\"uk-icon-arrow-right\"></i></a>"; uikit will handle all links with # as collapsible menu items: https://getuikit.com/docs/offcanvas.html live example: https://www.mistelbach-mustangs.at/
    2 points
  12. On the details tab of the field, look at Inputfield Type option, you should be able to switch between textarea / CKEditor.
    2 points
  13. Ah, should have looked more closely. Try this: $result = wireZipFile($zipfile, $foldertozip, array( 'exclude' => array( basename($config->paths->templates) . '/errors') ));
    2 points
  14. Thanks for reporting. I think it's kind of a mess The newest dev2 version doesn't have hooks (ready()) as to let the internal url for a page untouched. Therefor the replacing href urls on the render output and adding a request logic to redirect to the multisite url was necessary. Unfortunately this leads to problems to the setup you have. It currently assuming the multi domains are setup all in the root. I'm not seeing through all this as it gets kinda complex and not sure how the login can be changed to achieve what setup you have.
    2 points
  15. @flydev: The code in your first post needs to assign an array to the exclude option: $result = wireZipFile($zipfile, $foldertozip, array( 'exclude' => array( $config->paths->templates.'errors') )); From a quick glance at ProcessExportProfile, it looks like $dir is a relative path.
    2 points
  16. Is there a pressing reason to mix this level of layout into your content? Would separating the columns into individual textareas and moving the layout details into your templates work better?
    2 points
  17. Hi @bernhard, Sorry for the delay here - been hectic catching up with everything after getting back. I haven't played around too much yet, but I don't think it's going to be possible to have multiple console windows without hacking the Tracy core. If you want a quick preview of how it might work, change this line: https://github.com/adrianbj/TracyDebugger/blob/930b738e988239ac71fd76c23d565ba7dc091eeb/tracy-master/src/Tracy/assets/Bar/bar.js#L137 to: var win = window.open('', Date.now(), 'left=' + offset.left + ',top=' + offset.top It's just a quick hack to give each new window a different name. I am sure there will be side-effects though, so don't get too used to it Perhaps the better solution would be to implement my idea of adding a snippet manager to the console so that you could save and load (from a dropdown or similar) lots of different code snippets. You could run one, then easily load another one. I just need to figure out a nice interface for this so it's easy to find the snippet you are looking for when there are lots of saved snippets. I am happy to do something along these lines, but I am not sure I would want to lose the option for having the debug bar if I need it. Perhaps it could be toggled disabled be default (so it just shows that red power button like it does when you use the Tracy Toggler panel button or the Disable Tracy button in the Panel Selector. Do you think that would work for your needs?
    2 points
  18. Hi @mel47 - sorry for the delay on this. I have just committed a fix - could you please take a look and let me know if you have any other problems? I also fixed an issue with multiple values when you want a line break (\r) as the separator. I am converting \r to chr(13) and \n to chr(10). I know that \r works on Mac Excel, but from reading around I think you need \n for Windows, but you guys can test that out.
    2 points
  19. I've a function to clean out non URL conform chars.....since i had problems with the hashes in URL Segments this works for me: /* * create a valid url save one time token * */ function RandomToken($lenght = 32) { $p = new Password(); $h = $p->randomBase64String($lenght); $given = array("/", "."); $replace = array("_", "-"); $hash = str_replace($given, $replace, $h); return $hash; }
    2 points
  20. 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
  21. The docs for MSN do cover this. If your parent page has a particular template you can use the xtemplates and xitem_tpl options. For more advanced targeting you can use a hook, for example: $nav = $modules->get('MarkupSimpleNavigation'); $nav->addHookAfter('getItemString', function($event) { $page = $event->arguments('page'); if($page->children->count()) { $event->return = "<button class='$page->name'>$page->title</button>"; } });
    1 point
  22. Thanks for all those ideas @bernhard and @szabesz - You can already hide the debug bar by clicking the "x" at the far right of the bar, so I think that covers the "hide once" requirement. As for sticky - you need a way to restore, which is what the toggle button does, so I think I'll go for the toggled off by default on phone sized screens. I like the history idea and I wonder if an additional "Save Snippet" button could complement this such that snippets are automatically saved to history each time that first comment line is changed (maybe the last 5), and saved more permanently to a snippets library if you click the save button? Anyway, these are on my list and hopefully I can get to them shortly. Thanks again for the input!
    1 point
  23. The compiler, unfortunately, isn't really picky about things. It touches keywords like "require" and "include" inside and outside of the "real" PHP code, including comments. So, the quick solution would be to load hljs the classic way (<script src=...>).
    1 point
  24. woohoo thanks you! how I missed that - its working
    1 point
  25. Thanks horst, yes but it wont work. For information the core function add and test the trailing slash : if(count($options['exclude']) && (in_array($name, $options['exclude']) || in_array("$name/", $options['exclude']))) continue; Also I remember a detail, when I developed the profiles for Bootstrap and Foundation, I used ProcessExportProfile to export them, and this module try to exclude itself from the generated profile but it fail. So it look like an issue that is here since PW 2.7. // code from ProcessExportProfile [...] $options = array( 'dir' => $dir, 'exclude' => array("$dir/modules/ProcessExportProfile") ); [...]
    1 point
  26. $field->collapsed = Inputfield::collapsedNever; See here: https://processwire.com/api/ref/inputfield/#pw-methods-collapsed-constants
    1 point
  27. Download AdminOnSteroids.css and replace the one in your modules folder, or edit AdminOnSteroids.module and set a lower version number, eg. '98', then Refresh modules and finally check for updates.
    1 point
  28. 1 point
  29. May I join in? I think hiding it completaly is a valid request. When solely working on ftontend design, it just gets in the way on cramped display lik a mobile view. So maybe a "hide once / sticky hide" option in this case too? "multiple console windows vs snippets" Probably they are not the same. Snippets are pre made, but Bernhard is making up the snippets on the go and he wants Tracy to remember them, as fas as I get it, which would be useful for sure. We could even save them as snippets, should they happen to be useful Note, I'm not saying I badly need these features, I just wanted to point out a few things here.
    1 point
  30. iOS devices actually handle links with hover states quite well - first touch triggers hover behaviour. For Android/cross-platform check out @bernhard's solution: Using a hash in a link href is not great because it usually triggers a page jump when clicked. Using href="javascript:void(0)" is a bit better, but if you don't actually have an href you should probably be using a button element instead of a link. But my suggestion is if you're using Javascript to trigger your menu then just leave the parent href untouched and use preventDefault() in your Javascript. $('#my_link').click(function(e){ e.preventDefault(); // no page reload // show dropdown menu });
    1 point
  31. A typical way to do this sort of menu doesn't involve a hash in the parent href, but rather you use CSS to show/hide the nested lists of child pages. li > ul { display:none; } li:hover > ul { display:block; }
    1 point
  32. How about... foreach($pages->get("/filme/")->children() as $p) { $genres[$p->name] = $p->children("sort=random, limit=2"); } for($i = 0; $i <= 1; $i++) { foreach($genres as $genre) { if($genre->eq($i)) { echo $genre->eq($i)->title; } } }
    1 point
  33. @AndZyk - I can edit for you - just let me know what changes you need.
    1 point
  34. Thanks, just uploaded a fix to GitHub and the Modules directory (no version change). I haven't noticed this because I had Tooltips turned on.
    1 point
  35. Hello Beate, maybe this will help you: $films = $pages->get("/filme/"); foreach ($films->children as $category) { foreach ($category->children("sort=random, limit=2") as $film) { echo $film->title; } } It is not necessary to add all pages to one array, you could just loop trough them, if I understood you correctly. Regards, Andreas
    1 point
  36. I just used this, just that i used Ryan's suggestion for the random string $rand = new Password(); $hash = $rand->randomBase64String(100); and there is a problem with the second check here: if(strcmp(wire("users")->get($activate_username)->user_activation, $activate_hash) == 0 || wire("users")->get($activate_username)->user_activation == 0) If wire("users")->get($activate_username)->user_activation is a string starting with a letter it will be converted to integer 0 so the if statement is true, if the string starts with a number that number will be converted to an integer. To solve this use === in that comparison, or put 0 in quotes "0", or omit it altogether (if it's already 0 no need to set it again to 0). This is how i handle the activation: $username = $sanitizer->pageName($_GET["user"]); $hash = $sanitizer->text($_GET['hash']); // get the user $u = $pages->get("template=user, name={$username}"); // user exists if($u->id) { // check if user is activated if($u->user_activation === "active") { echo "Account is already active."; } // not activated compare hash from $_GET with hash from db // http://php.net/manual/en/function.strcmp.php else if(strcmp($u->user_activation, $hash) == 0) { // hashes are the same activate user echo "Your account has been activated!<br>"; $u->of(false); $u->user_activation = "active"; $u->save(); } // hashes don't match else { echo "There was an error activating your account! Please contact us!<br><br>"; } }
    1 point
  37. It is always important to eat your own dog food. It is interesting how coming to site design with PHPStorm at hands can change the whole API paradigm at once) As now we have at least 3 ways to call an API variable it would be incredibly important to have a detailed explanation about how to take a decision what to choose. Most of us used to use $page, but newcomers starting with demo profile will be using page(), and we are not even touching on wire() and $wire. It seems like @ryan is more into the function interface (you wouldn't be inventing it other way, would you). Please consider making an article about when to choose what, if you got time. I really like the regions functionality, but the + at the beginning and at the end seems magical and probably goes against the initial functional interface intention to have closer IDE integration. I do not think this could be advised by IDE (or am I missing something?) Is there or should there be other more convenient way to append and prepend to regions?
    1 point
  38. It appears that the last commits were quite incomplete, though the newer versions on my dev drive also had a few issues of their own. That's what you get when you replace sleeping with coding once too often I've updated both client and server module to 0.0.7 now, with partially re-written handshaking logic and a more detailed remote module list feature. I'll be quite busy the rest of the week (including the weekend), but if time allows, I want to tackle two issues in the first half of November: a cryptographic handshake - don't like really plaintext passwords going over the wire - and a documentation and an example module for the remote actions system. The latter will no bring up some more issues that needs fixing/tweaking along the way. My priority will be on my DatetimeAdvanced and JsonNativeField modules though, as I'll be using these in a production system in the near future, so I wouldn't ask anybody to hold their breath yet.
    1 point
  39. Oh, I have tried and loved larger formats. But one has to focus. I totally enjoyed the Hasselblad 500CM and Mamiya 7 and also explored larger 4x5 format with a Japanese wood camera. But I am restricted by a home bathroom-darkroom. Since my photography makes no money I prefer the costs of 35mm (both materials and darkroom equipment). Also all my photography is candid or with minimal interference making larger cameras and slower shooting an issue. The Leica M is my friend. Darkroom photography is on the rise again. Get over the longing and re-build your darkroom!
    1 point
  40. @Wanze I am still confused about the snippet of code for enabling dump(), I guess this function needs a class to be attached to, where do I add it? Edit: I have enabled it with the following code (in init.php) wire()->addHookAfter("TemplateEngineTwig::initTwig", function($event) { $twig = $event->arguments('twig'); $twig->addGlobal('hsaApp', wire('config')->hsaApp); $twig->addGlobal('hsaDist', wire('config')->hsaDist); $twig->addExtension(new \Twig_Extension_Debug()); }); Do you happen to know why `{{ dump(page) }}` results in a empty white page but for example `{{ dump(page.title) }}` works? Edit2: you need to install xdebug on php.ini
    1 point
  41. Anyone looking for some contract work? I have a few projects that I need help with. I have 8 upcoming projects (PW dev only) that need to be implemented. I would do all design and HTML/CSS. most of these are small to mid size sites with 5-10 templates. I would love to work with someone that wants to do a bunch of on-going contract work. I always have work . I am looking for someone that can write PW modules, is familiar with the PW way of doing things – and is completely happy with that. I have an existing project - PW site that I need some expert help on with the following features: tracking users actions & information on the site - saving to user profile. some FormBuilder integrations User favorites and recently viewed. adding some google charts to the admin backend - like a dashboard for some of the information we are collecting. making the admin/data easier to use for the clients. (organizational. I don't want to change PW at all) If you PM me, I can show you the site. I just don't want this forum post to get indexed by google if I put the URL or name.
    1 point
  42. Wanted to mention that there's a new dev version https://github.com/somatonic/Multisite/tree/dev2 that we are testing and using right now. It was tested and works with multilanguage and PW3 various features.
    1 point
  43. As promised, here's the script with delete powers. Only tested on a small subset of an installation I'm switching over to CroppableImage3 so do your own testing please!
    1 point
  44. Trekkerweb Supply & Demand https://markt.trekkerweb.nl/ Trekkerweb.nl brings agricultural mechanization news and supply & demand together in a single online platform for all the tractor and machine enthusiasts and others interested in the mechanization sector. The site is multi-language with English as default. None Dutch browsers will get the English version of the site, currently we are finetuning the German version which will be available somewhere in the near future. The search page in English and Dutch language - https://markt.trekkerweb.nl/search/ - https://markt.trekkerweb.nl/nl/zoeken/ Used modules Profields Table Profields Textareas MarkupLoadRSS (fetches brand related new from the main website) PageImageManipulator 2 (PIM2) (for placing watermark image) ProCache ProcessGetVideoThumbs TextformatterVideoEmbed WireMailSmtp LanguageSupport (Site is multi language: Dutch, German and Default English) Couple of custom made modules for user profiles and cross page linkage of the datamodel (Bower) components awesome-bootstrap-checkbox bootstrap-dropdowns-enhancement-sass bootstrap-sass bootstrap-select font-awesome formvalidation.io hashids jquery jquery-file-upload jquery-throttle-debounce jquery.mmenu js-cookie lifestampjs moment semantic-ui-sass verge Front-end user profiles (custom module) Account registration Customizable fields (in module settings) Per field privacy configurable (private, public, on a per user basis). Front-end login/ logout Reset password Email activation for account Request activation mail View profile Public profile Edit profile Set profile picture (cover image and avatar) Modify password Language choice Profile dashboard Front-end Ads management Create new ad Edit existing ad Manage media (images / video) Preview and approve ad Remove ad Data model Categories Subcategories Brands Input fields Options An intuitive data model drives the whole site. A couple custom made modules take care of the cross page assigning of categories to subcategories and brands. Per subcategory we are able to assign the related input fields and options which will be rendered on the 'Create new ad/ Edit ad' form page and combined with the given values rendered on the ad detail page. Database caching + Pro caching One of the challenges was to keep the whole project as low weight as possible. Since the data model with categories, subcategories, brands, inputfields and options is the backbone of the site we came up with the solution to have the names, titles, ids, and relations between them cached. Completely as json/javascript with pro cache and separated with database caching. With the Wire Fuel we made the $dm object available for accessing anywhere in PHP and globalJS.dm from within javascript. This means the whole data model is called only once per request, and while it exists in the database cache and pro-cache it is incredibly fast. Subcategory page The first image shown below represent one of the subcategories (Tractors) with assigned categories, brands, input fields and options. The image there after is a screenshot of the add ad page, where the input fields, options and brands are dynamicly rendered after being loaded via Ajax. Other features cookie based favourites cookie based last-viewed list advanced filter search related ads Thanks to the whole team (Ferdi, Bastiaan, Alex, John, Hessel) and last but not least Ryan for creating ProcessWire and all module developers out there
    1 point
  45. Infinity scroll kills linkability. With pagination you have at least some links (although content changes over time). Great site and photos!
    1 point
  46. Hi Guys I really like the Form API of Processwire, it is really flexible. You can build from a simple contact form until to a complex registration form in a short time without using HTML. The only "flaw" which I encountered is. The bigger the form is, the bigger the code gets and this can be frustrating when you are building forms with more than 20 Inputfields. The code gets longer and readability gets lost over the time since it is a (almost)self repeating process of "codeblocks" where the structure is almost always the same. So I decided to write up a simple class to "minify" the code when building forms with the form API. How does the class work? It is a very simply class where you create a new (didn't know how to name the class ^^)ProcessForm Object and get the InputfieldForm Object with the getFormObject() function. Now you can call the addInputfield() function to create any kind(not are all supported, only the simple ones) of Inputfield. And at the end you can render the ProcessForm object which basically calls the render() function of the InputfieldForm class. <?php $form = new ProcessForm("./contact", "post", "contactform"); //default ("./", "post", "ProcessForm") $form->addInput(array( 'type' => "InputfieldText", 'label' => "First Name", 'attributes' => array('id' => "firstname", 'name' => "firstname"), 'required' => 1 )); $form->addInput(array( 'type' => "InputfieldRadios", 'label' => "To much code for a simple Form?", 'options' => array('yes' => "Yes, absolutely", 'no' => "No, absolutely not"), 'attributes' => array('id' => "tomuchcode", 'name' => "tomuchcode"), 'required' => 1 )); $form->render(); ?> Is this usefull? Honestly said, I don't know if this is usefull for you. It is usefull for me, since I can "minify" or have a better overview/readability over my code. PS: I am still learning PHP OOP, so dont hate me when my "oop skills" are too low. I'am very open to better approaches, tipps, suggestions to improve this class or go antoher way to manage the big amount of code when building big forms with API. PPS: The class isn't tested very well(or better said it isn't tested at all ^^) since I am to lazy to do tests. So don't use this in commercial projects(but when you want still using it commercial it is at your own risk ^^). The code is on Github Greetings Orkun aka "Nukro"
    1 point
  47. Sorry for not replying. I was too busy, not only with updating this module. There's now a new dev version that fixes issues and improves some things. https://github.com/somatonic/Multisite/tree/dev For example the biggest change is that the configuration is now set in the config.php via an array in $config->MultisiteDomains $config->MultisiteDomains = array( "dev.domain.com" => array( // domain name can be used to map to root page "root" => "www.domain.com", // page name for the root page "http404" => 27 ), "dev.domain2.com" => array( "root" => "www.domain2.com", "http404" => 5332 ), ); This allows for different domain configurations on a dev and live stage, and since it's not in DB (via the module config) it can be easily transfered with a dump without worrying to overwrite or change the settings. Also there's no need to change the domain "root" pages name, as it's not directly coupled to the requesting domain. So you only change the array keys (=domain). Since the whole concept is all a pretty hack, I found that it comes with some complications that can't be solved in a elegant way. So for example the biggest issue is that you can't crosslink pages via the RTE Link plugin, since it doesn't know about Muiltisite. So you'll end with wrong URL's when for example link from a page of one site to a page of another site. If that's an issue it's still possible to copy the ProcessPageEditLink.module and modify the root parent for the page tree select. I'd be glad to help out with an example there. Further, the structure of a multisite install needs to be - Web (PW root page, I call it always "Web" since it isn't the homepage anymore) - www.domain.com (primary site home) - 404 Page - www.domain2.com (a second site home) - 404 Page ... I think I heard people were using a different structure in the current old version like: - Homepage (main site home) - About - Projects - 404 Page - www.domain2.com (second site home) - 404 Page - www.domain3.com (a third site home) - 404 Page ... But this wasn't ever recommended and it can lead to complications. ---- Again since this module is pretty much a hack, I'm not officially supporting and releasing this module. Use at your own risk. We use it in various projects now and while it works fine with all it's little drawbacks, the new version is little more solid. I would rather like to see if there's a way for a more integrated and supported way in the core. But not even sure how this could work out. Ryan may has some ideas or maybe thinks this isn't something PW could support. - Note that there's multisite core support, but it's for different DB's and "site" folders, but that's a different case altogether. Take care Soma
    1 point
  48. @hani, not sure about your query. But it is possible to write a SQL query that does compare two fields on pages. I'm no SQL guru either but I've done this in the past but didn't post. Here a example with two joins comparing two date fields on page: $query = "SELECT id FROM pages p LEFT JOIN field_mydate m1 ON p.id = m1.pages_id LEFT JOIN field_mydate2 m2 ON p.id = m2.pages_id WHERE m1.data > m2.data AND p.status < 2048"; $res = $db->query($query); $ids = array(); while($r = $res->fetch_array()) $ids[] = $r['id']; // fetch the ids $pa = $pages->getById($ids); // get pages foreach($pa as $p){ echo "<p>$p->title - $p->mydate - $p->mydate2</p>"; }
    1 point
×
×
  • Create New...