Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 10/06/2014 in all areas

  1. Hi everybody, I'd like to share a new module with you. Its purpose is to let users sign in with their Active Directory accounts using LDAP. It works similar to the module jimyost released in 2012, but adds some new features to it. You can define specific roles that are applied to new LDAP users Passwords are automatically updated by LDAP Local users still work like a charm You can translate it in the language you want to deploy your ProcessWire site New: Connect to a LDAP server via SSL New: Debug Mode New: Your configuration will be validated on save In my opinion, LDAP authentication is a must-have for ProcessWire being successful in the enterprise. What do you think? Is there a feature you miss? You can find the repository here: https://github.com/conclurer/LdapSignIn You can find the module in the ProcessWire module directory. Thanks in advance! Marvin Edit: Updated to Version 0.5.1 Beta including some minor fixes
    10 points
  2. Ok since some different things are up to the client now - but the main work was done i'd like to show my first work with PW and give some feedback and kind words about the workflow. First i've to say thank you - ryan for this awesome diamant of code and all members here that treat every other with respect and patience! Domain is not open until some bureaucratic things are ready. http://gs-altfraunhofen.de/ This was no big project but not really easy, since there was no real basic stuff to start with, and the existing things (like a strange version of the logo you could see now) are done by some teachers and changing them was a little hot political thing....hot pavement! For such a little project with less budget i give the easy http://purecss.io/ a try and work with that. Tried to give the website some individual notes, but stay with many given elements by the small CSS Framework (buttons, forms) to save time/budget for the client. Here some screenshots of the page and changing on responsive: Desktop Mobile Backend Some special modules that i used: FieldtypeEvents (with some changes) FormTemplateProcessor (with adding some spamdetection, hidden honeypot and a "leave blanc" field) MarkupSimpleNavigation PageListImageLabel ProcessAdminCustomPages VersionControl Some special adjustments and using of some modules: FormTemplateProcessor Get a Form from given fields in a backend template and save them as pages and/or send them to a mailadress....easy task with the FormTemplateProcessor. For some spamdetection a added a hidden field as a honeypot and a questfield to leave blanc to check against bots. //Changes for better Spamprotection with a hidden additional field as a honeypot // create a text input a hide it via CSS .Inputfield_name2 display:none - see CSS example on the end of this module $field = $this->modules->get("InputfieldText"); $field->label = "Name2"; $field->attr('id+name','name2'); $field->required = 0; $form->add($field); // append the field to the form //end changes /**and at the end**/ //Create a field quest in the form template with heading like "please show us youre human an leave this blanc" //Set the Spamfilter and check if field quest or spam are blank! $questfield = $this->input->post->quest; $spamfield = $this->input->post->name2; if(empty($spamfield) && empty($questfield)) { echo "<h3>Ihre Email wurde gesendet!</h3>"; // see if any errors occurred if(count($form->getErrors())) { // re-render the form, it will include the error messages $out .= $form->render(); } else { // successful form submission, so populate the new page with the new values. foreach($form as $field) { $this->contact->set($field->name, $field->value); } if($this->email) $this->sendEmail($form); //if($this->parent) $this->savePage($form); $out .= $this->successMessage; } return $out; } else { echo "<h3>Es ist ein Fehler aufgetreten - Sie haben das letzte Feld ausgefüllt bitte versuchen Sie es erneut!</h3>"; } //end changes Frontend Backend ProcessAdminCustomPages This is a real great module for custom made admin pages. You simple add a page to the admin setup the process and add a templatefile in your site folder! Admin stuff made easy even for non devs! example code from the imageoverview (CutomAdminPage Template): <?php // Bilderübersicht Custom Admin Page ?> <style type="text/css" media="screen"> /** * larget magnific popup */ .mfp-iframe-holder .mfp-content { max-width: 1200px!important; } </style> <script type="text/javascript"> $(document).ajaxComplete(function() { //add trigger class and modal setup $('.PageListActionEdit a').each(function(){ $(this).addClass("lb-edit").attr("href",$(this).attr('href')+"&modal=1"); }); $('.PageListActionNew a').each(function(){ $(this).addClass("lb-edit").attr("href",$(this).attr('href')+"&modal=1"); }); //setup lightbox $('.lb-edit').magnificPopup({ type: 'iframe', disableOn: 0 }); }); </script> <?php //get Magnific css and js $this->modules->get('JqueryMagnific'); //render PageListtree with setting the parent page $formImages = $this->modules->get('InputfieldForm'); // prep the form $wrapperImages = new InputfieldWrapper; // a wrapper $wrapperImages->attr('value', '<h2>Bilder</h2>'); $i = $this->modules->get('ProcessPageList'); // get the pagelist process $i->set('id', 1015); // setting the parent page $pageTreeImages = new InputfieldMarkup; // the placeholder $pageTreeImages->value = $i->execute(); // fill the InputfieldMarkup form field... $wrapperImages->add($pageTreeImages); // put inside the wrapper... $formImages->append($wrapperImages); // append the wrapper echo $formImages->render(); And as result i've a adminpage just with the imagetree. For this kind of websites where i've very less images and use it on different pages - i'd like to have a mediacenter - and this is the way i get it work. Using the image approach from somas imagemanger module: https://processwire.com/talk/topic/3219-images-manager-beta/ But only the setup for the templates (single image fields and cats) - and have an easy administration like the whole site in a PW style. One bad thing with a own usage of the ProcessPageList - while editing after save you will be redirected to the "real pagetree" not the custom one! So no problem, it would be much better to use a kinda a modal editing on this special content - no problem all there just to find and use. (Combined it with the PageListImageLabel to show some thumbs in the pagetree) For the images first i thought i change the Tree where in the Wysiwyg the image is choosen to insert - this works so far mor details here: https://processwire.com/talk/topic/7439-processpageeditimageselect-hook-and-change-default-page/ But then i decided to don't let the users handle images in the wysiwyg and added a fieldset TAB for images and populate them if the users choose some on the right place on every page. So i've with a Pageselect field (parent page is the image-root) a simple "click on the images to show gallery" possible on every page: Here some screens on the backend of the custom admin page for the images with the template from above: Did the same for the documents section where i again use soma setup for files as pages: https://processwire.com/talk/topic/4602-flexible-downloads-using-pages/ This is a real great tutorial - you can expand all you need for such documents for eg. a counter is simple as easy PHP: 1. Setup a single file field, a counter integer field and a template for the kind of files you are using f.e. doc.php, docx.php, pdf.php and now use such a template file <?php /** * doc.php */ if($page->doc){ $page->of(false); $page->counter += 1; $page->save(array("quiet" => true)); $page->of(true); wireSendFile($page->doc->filename, $options); } Benefits from files as pages are real SEO Links on documents and images like: http://gs-altfraunhofen.de/dokumente/morgenbetreuung.doc/ some tweaks on the contact-page and some others in the admin.php to get them always in the state i want them i've some code like this: /** * setup choosen templates to hidden - equal witch setting the user takes */ $pages->addHook('saveReady', null, 'makePageHidden'); function makePageHidden(HookEvent $event) { $page = $event->arguments(0); if($page->template != 'doc' && $page->template != 'docx' && $page->template != 'pdf' && $page->template != 'image-category' && $page->template != 'image' && $page->template != 'contact_form') return; // replace 'category-site' with your template name if(!$page->is(Page::statusHidden)) $page->addStatus(Page::statusHidden); } For me like wrote i'm not a developer, not a real good coder, but i like the way that PW (and this awesome community) teach me in the right direction and let me be free in the way to solve my challenges! So closing the circle and say again thank you to all that read this and contribute to PW and this forum! Have fun - best regards mr-fan
    8 points
  3. OK, I have gone ahead and customised Batcher to do this. Almost ready but there are a few kinks (js/css). The 'Tag' action is hidden on load (similar to Change Parent) but it is not hidden on selection of a different option; js is not my forte. PW API side works fine although you may want to limit the number of pages you apply batch tags to. You can apply single or multiple tags. There are also some hard-coded things in there that you might want to change such as the name of your 'tags' field. Just search for @@kongondo in the ProcessBatcherExt.module and ProcessBatcherExt.css files for changes I added. Feel free to do with it as you please BatcherExt.zip
    7 points
  4. Thank you so much for this kongondo! The work you did in there is fantastic. Well I'm not much of a javascripter but I may be able to tweak the code a bit. I'll need to read through everything to make sure, but this is going to totally save my baccon. YOU ARE MY HERO. I'll try and post back anything I come up with. *** People such as yourself are what make processwire amazing!
    4 points
  5. How about this (untested)... $categories = $page->children; /** * This will hold unique values from the possible repeats in your page tree... */ $uniques = array(); /** * Iterate as you did before but only keep one copy of each category you visit. */ foreach ($categories as $category) { $categoryNames = $category->categories; foreach ($categoryNames as $categoryName) { $uniques[$categoryName->id] = $categoryName->title; } } /** * Now do what you want with the uniques. They are indexed by page id. */ foreach ($uniques as $id => $title) { echo $title, "<br />\n"; } ...?
    4 points
  6. Yes...IMO, seems like you are unnecessarily complicating matters with something like /employees/edit/14 Of course you know this is how PW does it.../mysite/myadmin/page/edit/?id=5094. How many people really care about pretty URLs in the backend?
    3 points
  7. thanks for the help guys kinda figure it out had to make images field then upload then call it using <img src=<?php echo $page->my_imagefield->url; ?> /> sorry for the trouble , im such a noob hehe
    3 points
  8. $tagSelectField = $modules->get("InputfieldSelectMultiple"); $tagSelectField->label = __("Tags:");//note the translation string change from your original code $opts = $pages->find('template=tag, include=all'); foreach($opts as $opt) { $tagSelectField->addOption($opt->id, $opt->title); } $tagSelectField->attr('id+name', 'recipeTags'); $form->apend($tagSelectField); Edit. There might be lots of tags though...so you might want to use a different inputfield, maybe autocomplete...But don't know if autocomplete will work in the frontend!
    3 points
  9. Hi all, this is a site we have just released, the first we have done using ProcessWire: http://www.ht-heizelemente.de Here's the modules that we used: - AIOM: very useful to minify and concatenate script and css - Alternative Grid Images: good to have image gallery with custom image dimensions - MarkupSitemapXml: simple but effective module that outputs a sitemap.xml As you can see, we didn't use a lot of modules simply because PW is so powerful we didn't have the need to use many of them... I have to say I am very happy with this cms, thanks to ryan and other developers (and the community too) for this great product!
    3 points
  10. Since you guys asked for it, I'll take a stab at a case study on the development process. Most of the development was done in about a week and a half. I started with the basic profile, but it ended up being something somewhat similar to the Blog profile in terms of how it's structured. Below I'll cover some details on the biggest parts of the project, which included data conversion, the template structure, the front-end development and anything else I can think of. Data Conversion from WordPress to ProcessWire One of the larger parts of the project was converting all of the data over from WordPress to ProcessWire. I wrote a conversion script so that we could re-import as many times as needed since new stories get added to cmscritic.com almost daily. In order to get the data out of WordPress, I queried the WordPress database directly (my local copy of it anyway) to extract what we needed from the tables wp_posts for the blog posts and pages, and then wp_terms, wp_term_relationships, and wp_term_taxonomy for the topics and tags. WordPress stores its TinyMCE text in a state that is something in between text and HTML, with the most obvious thing being that there are no <p> tags present in the wp_posts database. Rather than trying to figure out the full methodology behind that, I just included WP's wp-formatting.php file and ran the wpautop() function on the body text before inserting into ProcessWire. I know a lot of people have bad things to say about WordPress's architecture, but I must admit that the fact that I can just include a single file from WordPress's core without worrying about any other dependencies was a nice situation, at least in this case. In order to keep track of the WordPress pages imported into ProcessWire through repeat imports, I kept a "wpid" field in ProcessWire. That just held the WordPress post ID from the wp_posts table. That way, when importing, I could very easily tell if we needed to create a new page or modify an existing one. Another factor that had to be considered during import was that the site used a lot of "Hana code", which looked like [hana-code-insert name="something" /]. I solved this by making our own version of the Hanna code module, which was posted earlier this week. Here's an abbreviated look at how to import posts from WordPress to ProcessWire: $wpdb = new PDO("mysql:dbname=wp_cmscritic;host=localhost", "root", "root", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'")); $posts = wire('pages')->get('/posts/'); $sql = " SELECT * FROM wp_posts WHERE post_type='post' AND post_status='publish' ORDER BY post_date "; $query = $wpdb->prepare($sql); $query->execute(); while($row = $query->fetch(PDO::FETCH_ASSOC)) { $post = $posts->child("wpid=$row[ID]"); // do we already have this post? if(!$post->id) { // create a new post $post = new Page(); $post->template = 'post'; $post->parent = $posts; echo "Creating new post...\n"; } $post->of(false); $post->name = wire('sanitizer')->pageName($row['post_name']); $post->title = $row['post_title']; $post->date = $row['post_date']; $post->summary = $row['post_excerpt']; $post->wpid = $row['ID']; // assign the bodycopy after adding <p> tags // the wpautop() function is from WordPress /wp-includes/wp-formatting.php $post->body = wpautop($row['post_content']); $post->save(); echo "Saved post: $post->path\n"; } What I've left out here is the importing of images, topics, tags, and setting the correct authors for each post. If anyone is interested, I'll be happy to go more in depth on that, but didn't want to overwhelm this message with code. Template File Structure This site makes use of the $config->prependTemplateFile to automatically include the file _init.php before rendering a template file, and $config->appendTemplateFile to automatically include the file _main.php after. So the /site/config.php has this: $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; You may recognize this as being the same setup from the Skyscrapers profile. The _init.php includes files containing functions we want to be available to all of our templates, and set default values for the regions we populate: /site/templates/_init.php /** * Include function and hook definition files * */ require_once("./includes/render.php"); require_once("./includes/hooks.php"); /** * Initialize variables populated by templates that get output in _main.php * */ $browserTitle = $page->get('browser_title|title'); $body = "<h1>" . $page->get('headline|title') . "</h1>" . $page->body; $side = ''; $renderMain = true; // whether to include the _main.php file The includes/render.php file that is included above includes several functions for generating markup of navigation and post summaries, or any other shared markup generation functions. Examples are renderPost(), renderNav(), renderTags(). This is similar to the blog.inc file from the Blog profile except that I'm letting these functions generate and return their own markup rather than splitting them into separate view files. I personally find this easier to maintain even if it's not as MVC. The includes/hooks.php sets up any hooks I want to be present for all of my templates. I could have also done this with an autoload module, but found this to just be a little simpler since my hooks were only needed on the front-end. The main hook of interest is one that makes all posts look like they live off the root "/" level rather than "/posts/" (where they actually live). This was in order to keep consistency with the URLs as they were in WordPress, so that the new site would have all the same URL as the old site, without the need for 301 redirects. /site/templates/includes/hooks.php /** * This hook modifies the default behavior of the Page::path function (and thereby Page::url) * * The primary purpose is to redefine blog posts to be accessed at a URL off the root level * rather than under /posts/ (where they actually live). * */ wire()->addHookBefore('Page::path', function($event) { $page = $event->object; if($page->template == 'post') { // ensure that pages with template 'post' live off the root rather than '/posts/' $event->replace = true; $event->return = "/$page->name/"; } }); Our /site/templates/_main.php contains the entire markup for the overall template used site wide, from <html> to </html>. It outputs those variables we defined in _init.php in the right places. For example, $body gets output in the <div id='bodycopy'>, $side gets output in the right <aside>, and $browserTitle gets output in the <title> tag. /site/templates/_main.php <?php if($renderMain): ?> <html> <head> <title><?=$browserTitle?></title> </head> <body> <div id='masthead'> // ... </div> <div id='content'> <div id='bodycopy'><?=$body?></div> <aside id='sidebar'><?=$side?></aside> </div> <footer> // ... </footer> </body> </html> <?php endif; ?> We use the rest of the site's template files to simply populate those $body, $side and $browserTitle variables with the contents of the page. As an example, this is an abbreviated version of the /site/templates/post.php template: /site/templates/post.php // functions from /site/templates/includes/render.php $meta = renderMeta($page); $tags = renderTags($page); $authorBox = renderAuthor($page->createdUser); $comments = renderComments($page); $body = " <article class='post post-full'> <header> <h1>$page->title</h1> $meta </header> $page->body $tags $authorBox $comments </article> "; if(count($page->related)) { $side = "<h4>Related Stories</h4>" . renderNav($page->related); } What might also be of interest is the homepage template, as it handles the other part of routing of post URLs since they are living off the root rather than in /posts/. That means the homepage is what is triggering the render of each post: /site/templates/home.php if(strlen($input->urlSegment2)) { // we only accept 1 URL segment here, so 404 if there are any more throw new Wire404Exception(); } else if(strlen($input->urlSegment1)) { // render the blog post named in urlSegment1 $name = $sanitizer->pageName($input->urlSegment1); $post = $pages->get("/posts/")->child("name=$name"); if($post->id) echo $post->render(); else throw new Wire404Exception(); // tell _main.php not to include itself after this $renderMain = false; } else { // regular homepage output $limit = 7; // number of posts to render per page $posts = $pages->find("parent=/posts/, limit=$limit, sort=-date"); $body = renderPosts($posts); } The rest of the site's template files were handled in the same way. Though most were a little simpler than this. Several were simply blank, since the default values populated in _init.php were all that some needed. Front-end development using Foundation 4 The front-end was developed with the Foundation 4 CSS framework. I started with the Foundation blog template and then tweaked the markup and css till I had something that I thought was workable. Then Mike and I sent the _main.php template file back and forth a few times, tweaking and changing it further. There was no formal design process here. It was kind of a photoshop tennis (but in markup and CSS) where we collaborated on it equally, but all under Mike's direction. After a day or two of collaboration, I think we both felt like we had something that was very good for the reader, even if it didn't originate from a design in Photoshop or some other tool like that. I think it helps a lot that Foundation provides a great starting point and lends itself well to fine tuning it the way you want it. I also felt that the mobile-first methodology worked particularly well here. Comments System using Disqus We converted the comments system over to Disqus while the site was still running WordPress. This was done for a few reasons: Disqus comments provide one of the best experiences for the user, in my opinion. They also are platform agnostic, in that we could convert the whole site from WP to PW and not have to change a thing about the comments… no data conversion or importing necessary. Lastly, ProcessWire's built-in comments system is not quite as powerful as WordPress's yet, so I wanted cmscritic.com to get an upgrade in that area rather than anything else, and Disqus is definitely an upgrade from WP's comments. In order to ensure that Disqus could recognize the relations of comment threads to posts, we again made use of that $page->wpid variable that keeps the original WordPress ID, and also relates to the ID used by the Disqus comments. This is only for posts that originated in WordPress, as new posts use a ProcessWire-specific ID.
    2 points
  11. Description This module adds icons based on the file type uploaded. It also lets you change the columns, etc. You can watch the video for more details or download and install. To make it work (do not know why) you have to change any configuration setting and save. Version Alpha version (0.0.1). Updated: 0.0.2 - Added Json name shorter, icons and columns. Updated 0.0.3 - Config in columns Updated 0.0.4 - Video and Audio extensions added. Updated 0.0.5 - Fixed select files and drag to upload div position. Updated 0.0.6 - Execution of the module only in the administration. What a fail! Github
    2 points
  12. Hello everyone, Thank you for your fast answers. Looks like there's definitely a need for an extended LDAP module. @teppo: Yes, I'll enhance the module's functionality over time. For ideas and feature wishes, you can just open up tickets on GitHub. Furthermore, if you can extend the module's functionality, you can open up a pull request on GitHub at any time. @horst: Thank you for finding the spelling mistake. I'll fix that one in the next update. @Pete: This is heading in the same direction as teppo's thoughts. Maybe in addition to mapping the groups into different ProcessWire roles, mapping some user-defined Active Directory attributes to ProcessWire user variables could be a nice extension. I'd be glad if we could talk about this in a separat GitHub thread so that this does not interrupt this one. The idea with the GUID is nice, although it needs an additional field in the user model and I'm not sure if that is a proper way to solve this issue. @Nico Knoll: Of course I'm German. How could you be unable to see that. ;-) I work together with @phil at Conclurer.
    2 points
  13. Here's a script that I've been using on our sites and recently enhanced to also handle the conversion from TinyMCE to CKEditor in ProcessWire 2.5. It's a sort of "global config" for CKEditor, which allows you to change the settings for all CKEditor fields at once. Note: This one will automatically update all CKEditor fields unless they are explicitly excluded in the config ($excludedFields). If you want it to change TinyMCE fields into CKEditor fields, make sure $replaceTinyMCE is set to true in the config section of the code. <?php include('./index.php'); // Config $excludedFields = ""; // List of fields to exclude, separated by pipe (i.e. "body|sidebar") $replaceTinyMCE = false; // true|false If true, converts any fields using TinyMCE to use CKEditor instead // Change any fields using TinyMCE to use CKEditor instead if($replaceTinyMCE) { foreach(wire("fields") as $field) { if($field->type == 'FieldtypeTextarea' && $field->inputfieldClass == 'InputfieldTinyMCE') { $field->inputfieldClass = 'InputfieldCKEditor'; $field->save(); } } } // Get all fields using CKEditor $fields = new WireArray(); foreach(wire("fields") as $field) { if($field->type == 'FieldtypeTextarea' && $field->inputfieldClass == 'InputfieldCKEditor') { $fields->append($field); } } // Exclude any fields specified above $fields = $fields->find("name!=$excludedFields"); // Apply settings foreach($fields as $field) { $field->contentType = "1"; // 0="Unknown", 1="Markup/HTML" $field->rows = "15"; // The number of rows initially shown for this field. $field->toolbar = " Styles Undo, Redo Bold, Italic, -, RemoveFormat NumberedList, BulletedList, -, Blockquote PWLink, Unlink, Anchor PWImage, Table, HorizontalRule, SpecialChar PasteText, PasteFromWord Scayt, -, Sourcedialog "; $field->inlineMode = "0"; // 0="Regular Editor", 1="Inline Editor" $field->textformatters = array("TextformatterHannaCode","TextformatterVideoEmbed","TextformatterSmartypants"); // Accepts ordered array of module names $field->useACF = "1"; // 0="No", 1="Yes" $field->usePurifier = "1"; // 0="No", 1="Yes" $field->extraAllowedContent = ""; $field->formatTags = "p;h2;h3;h4;h5;h6"; $field->contentsCss = ""; // Path to your css file, i.e. "/site/templates/styles/contents.css" $field->stylesSet = ""; // Path to js file containing stylesSet, i.e. "mystyles:/site/modules/InputfieldCKEditor/mystyles.js" $field->customOptions = ""; // Custom Config Options $field->extraPlugins = "pwimage,pwlink,sourcedialog"; $field->plugin_sourcedialog = ""; // Sourcedialog settings $field->removePlugins = "image"; $field->save(); } ?> CKEditor is now updated. Updated fields: <? foreach($fields as $field) echo $field.', ' ?> To use the script, simply copy the above code into a file in the root directory of your ProcessWire installation, and name it something like "ckupdater.php". Edit the configuration settings under the "Apply settings" section how you'd like, (I've done my best to briefly document how these work--at least the more confusing ones). To run the updater, just go to www.yoursitegoeshere.com/ckupdater.php. It will confirm the update and tell you which fields were effected. Hope this helps someone out!
    2 points
  14. I don't think it matters really in an admin context I don't think it's old school and that PW is a not-modern framework. It's a kind of its own. It may feel different when coming from other frameworks (I see that, as PW is not my first CMS or Framework), but then I embrace what PW is giving us. Never will everybody 100% agree with design decision made by Ryan, but then it's with everything and after all it's here to discuss and may be extend on a solid base. It's living software and forum. See it as Ryan is listening and giving his view on things, it's what he likes. And if there's something that makes a lot of sense he doesn't restrain from adding it. Need a method to be hookable that isn't? Don't be afraid to question it and ask to add it, after all it's just three underscores to add.
    2 points
  15. http://webscripts.softpedia.com/
    2 points
  16. @mr-fan, Thank you for your wonderful response to my question. I did not know about the "field dependencies" option (I saw it in the admin, but did not understand the use case for it... but now you have explained it very well to me!) I think that is a great solution for some sites. The only drawback, as you said, is users cannot re-order them above and below each other. The new module I am building uses the PageTableExtended field, and I would only expect to have 6-8 "block types" per site (if you remember in Concrete5, there are about 20 included with the core system, but most of those are not used by clients in my opinion and instead are there for system functionality like autonav, page_list, and search). I think you will really like the module I am building because it will fill that role of letting you set up some custom content blocks that your users can re-order on the page (drag up and down). As Soma says, it will not be good for a site with 1,000's of pages, but for smaller sites (like company or non-profit organization information site) I think it will be very helpful. Thank you again for giving me great info about how I can use ProcessWire. I really like the system so far and the community in the forums is very helpful. Cheers, Jordan
    2 points
  17. Thanks for this, Marvin! To answer your question, proper LDAP module is definitely something we need. Taking a quick look at your code, this seems like a reasonable tool for simple use cases, which brings me to my question: do you have any plans for incorporating slightly more advanced features, such as defining roles based on AD groups (including nested groups, which is surprisingly often missed altogether), automatically closing sessions for users no longer found from AD, etc.? In my opinion those are (some of the) must-have features in order for this module to answer those "enterprise use cases" you've mentioned Also, as a minor (?) detail, ability to specifically define search base would be great (and, again, a must-have feature in certain setups).
    2 points
  18. Try this in the 'custom php code input' $author = wire('user')->id; return $pages->find("template=server, created_users_id=$author");
    2 points
  19. You'e browsed https as scheme, but the script's & styles are appended with http:// that's the reason it failed to include.
    2 points
  20. I'm missing this feature - in my case I have an "Active" checkbox on some items, and want new items to be active by default. "Inactive" in my case wouldn't make much sense, and I'm also not fond of the double negation... "not inactive" - that's poor semantics.
    2 points
  21. Just a small detail but for "behind" the scenes hooks and such thing you don't need a Process module. Those are for admin pages that have a process added (the module). The ___execute is for returning markup that should show on the admin page with this process. You would create a simple WireData module like the HelloWorld.module. And you don't need that ProcessPageTrash module, that is also an admin page to delete trashed pages. So you need a WireData module that autoloads, Process module shouldn't ever be autoload. autoload on a selector "process=ProcessPageList" doesn't work, and if at all I think it's not suitable cause that's a module working mostly with ajax. Not 100% sure without trying. autoload=>true should be sufficient. You check anyway what you want to delete and already add the hook to users. $this->users->addHookAfter('delete', $this, '___execute()'); // is this correct This is a hook for when a page was deleted, but afterwards, so you never know what page was deleted. May it would be better to use addHookBefore("delete", $this, "hookDeleteUsers"); Then not "___execute()" but a custom function, and you use the $event to catch the page being deleted public function hookDeleteUsers($event){ $userpage = $event->arguments("page"); if($userpage->id){ // do some stuff example $userPage = $pages->get("created_users_id={$userpage->id}"); $this->pages->trash($userPage); } } http://cheatsheet.processwire.com/?filter=trash
    2 points
  22. If you go the urlSegment REST like routing you could still ensure and set the maxUrlSegment for your module. This for example would work out: <?php class MyHelper extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'MyHelper', 'version' => 1, 'summary' => '', 'singular' => true, 'autoload' => "Process=ProcessHello", // only load on your module ProcessHello ); } public function init() { $this->config->maxUrlSegments = 7; // more ? } } It's not possible from an non autoload Process module to overwrite it but a little helper module would do fine.
    1 point
  23. Are you calling the owl slider? You should have this on your page somewhere: $(document).ready(function() { $("#owl-demo").owlCarousel(); }); It sounds like your loop is working fine, so this is not a PW problem but possible an issue with initialising the script and so on. Again, check the console in chrome to see if it is showing any JS errors.
    1 point
  24. Glad you solved it. So, your submit button didn't have a name....been there ...
    1 point
  25. Remember that you can use more than just one Process module and admin pages hierarchically in the admin. Don't limit yourself to one module or admin page. Also each admin page (nested maybe) can have the same process module attached. Not sure if that would be helpful at all but it's very well possible. I see what you mean with the routes and how they can be used in a REST-like structure. I think if you try to rebuild those you're left with trying urlSegments, but maybe not. I would suggest to try and experiment some time before you deciding on something. Up to you. I mean adding or editing a page can be something like using the ProcessPageEdit and ProcessPageAdd in your module. As you said it's just pages and templates and fields, you already have the - and can extend the crud, and you can use what is there or build completely your own things. Everything fits nicely together with admin modules, Pages, Templates, Fieldtypes and Inputfields. It took some time to get into, but I'm maybe not the best person to advocate all this. Lister and Lister Pro is something that may be of interest for you also, cause it can build Admin pages simply by entering a Name in the module settings and click "add". It will generate a new Lister admin page, that can list pages/entries with the InputfieldSelector field type Ryan built, that let's you build filters/selectors for what to list, you then can edit or add pages etc, run actions (also add your own action modules you can build and extend on) on the results. It's what is new in PW 2.5 and the light version is now in Users and Admin page search. The pro version might also be available soon. It seems all to go very far and is complex, but also shows what's possible. I would try to study some process modules in core and what Ryan have built. But feel free to try implement your way of working, just keep in mind that maybe with a more PW way you also can ensure it will be more "compatible", if that's really an issue. Ryan said once Process modules are just mini apps inside PW, and they can be verstaile and modular. I'm not sure Ryan was ever into REST-like routing, as it's also not something that is an absolute best way.
    1 point
  26. I modified and quickly tested this example from SO: http://stackoverflow.com/questions/7849478/how-to-process-multiple-forms-using-one-php-script and it works fine...(but haven't tested with processInput). Make sure your PHP/PW form logic is at the top of the template file btw... <?php if (isset($input->post->submitForm2)) { echo '<pre>'; print_r($input->post); echo '</pre>'; echo 'Yes'; } ?> <form action="" name="form1" method="post"> <input type="text" value="" name="A" /> <input type="text" value="" name="B" /> <input type="text" value="" name="C" /> <input type="text" value="" name="D" /> <input type="Submit" value="Submit Form" name="submitForm1" /> </form> <form action="" name="form2" method="post"> <input type="text" value="" name="A" /> <input type="text" value="" name="B" /> <input type="text" value="" name="C" /> <input type="text" value="" name="D" /> <input type="Submit" value="Submit Form" name="submitForm2" /> </form> <form action="" name="form3" method="post"> <input type="text" value="" name="A" /> <input type="text" value="" name="B" /> <input type="text" value="" name="C" /> <input type="text" value="" name="D" /> <input type="Submit" value="Submit Form" name="submitForm3" /> </form>
    1 point
  27. So if you remove all that code, it is gone? You can also use $runtimer = Debug::timer(); ... code $runtimer = Debug::timer($runtimer); echo "Time: $runtimer"; Edit: corrected syntax...
    1 point
  28. Oh, I did not explain that clearly. Yes, I will use "executeSomething()" for the "top-level" url of a certain controller (or data entity). For example, if I have something like "employees" and "joblistings", the I can have "executeEmployees()" and "executeJoblistings()". But within each of those sections, there are several different actions one might take... you might want to display the list of all employees or jobs, then be able to add a new employee or job, edit or delete an existings one. Ideally then my url structure would be /employees (to list all employees), /employees/add (for the form that lets you add a new employee record), /employees/edit/14 (to edit the existing employee record having id "14"), etc. So as you can see there is the need for several addition url segments. It gets even trickier if my data relationships are such that an employee can only exist under 1 job record... in this case I might have /jobs/27/employees/add (to show a form for adding a new employee to job #27). What I am hearing from your answers is that I should not rely on the url segments for this routing, but instead I must do something like /employees?path=edit/14 , or perhaps something like /employees?action=edit&id=14 (that is probably better now that I think about it). By the way, the "employees" and "jobs" is just for example -- I know that in ProcessWire I should actually instead create pages and templates to manage something like this. I guess this is why my issue does not come up often, because it can usually be bypassed by using PW's existing pages/templates/fields system. But since I am trying to create an editing interface that is for manipulating pages/templates/fields themselves, it is too confusing for me to wrap my head around how to use pages/templates/fields to manage themselves... so I am reverting to the method I am most familiar with.
    1 point
  29. Makes sense. That's also roughly the same thing as what Antti is doing in his Facebook Login module, comparing against custom facebook_id field instead of name
    1 point
  30. er... not knowing exactly what your set up here is, but it sounds like you are basically grabbing a huge amount of information and then trying to deal with it. But I cant see where that is happening. Now, your database query (find) it is looking for what exactly? The fact that you have used this script before sound like the problem may be in the quantity you are dealing with in this case, or something like that. In other words, not so much what you are returning but what you are searching. If the CPU usage is rocketing, then it sounds like you are getting stuck in a loop somewhere - searching on itself or something. Can you refine the search in anyway to make it more specific?
    1 point
  31. Hi @Soma, You're "reboot" explanation is very clear and explains things quite well -- thank you for writing all that out, it is very much appreciated! I create a lot of "CRUD" applications in CMS dashboard, where you have lists of records, then you view sub-records of those, and you add/edit/delete... each of these operations requires its own form/page. And I am used to other systems where you try to map the URL's to the data entities (this is what I believe I meant by saying "REST-like routing", but I could be using the wrong term there... that's just how I think of it). Ruby on Rails is the big one, but since Rails was released it seems that almost all other PHP frameworks are using a similar style (CakePHP, CodeIgniter, Symfony, Kohana, Laravel, etc.). So that's what I meant by "more modern system"... not that PW isn't modern, but I do think that the lack of REST-like routing in the admin modules is definitely how things were commonly done before Rails, but it is not so common anymore. Not saying it is bad, just different I think I can easily recreate the routing style I am used to (along with sub-folders in my module for "controllers", "models", and "views"), and I just need to pass around the "path" as a querystring argument instead of looking at the actual URL segments. This way I can have as many url segments as I want, and I do not have to worry about the maxUrlSegments setting at all. Overall, I like that ProcessWire does not try to impose its own architecture on you too much (of course there is some but that is unavoidable in any system). Overall it seems to "get out of your way" which is very good for experienced developers like us who already have strong ideas about how we like things to work for us. Thanks again, I really do appreciate your help as I learn this new system!
    1 point
  32. So let's start again. 2. is wrong and is what got me partly confused (apart from not knowing the multiple url segment after a executeSomething()) You can't add url segments to execute() base url of your module /admin/mymodule/ it would give you a unrecognized path. What also got me confused and can't agree, is I'm not sure I understand your statement that the current admin Process modules need a more roboust routing? Or maybe I don't understand. I find them very robust and flexible. I don't think it's ever meant to be used extensively with urlSegments rather than url params if many params are needed. I think you can assume that at least 1 urlSegment is given as you can't set it to 0, or processwire admin won't work cause the executeSomething() methods are internally using urlSegments (as I see now). I'm not sure what you mean with url segment level? I think you mean the maxUrlSegments in config? You could either check for the max setting in the init() and throw an exception or $this->error(message) to the admin that they need to up their setting. Default is 4 and if you really need more (unlikely) you could set that config value using an simple autoload module. I think Ryan isn't using urlSegments in admin extensively other than checking in the init(), if you're on executeSave() "save" and maybe load conditional modules that need to be loaded in the init() because of required load order and it would be too late in the executeSomething(). I'm not sure what Ryan thinks about using urlSegments in admin at all. He still thinks Process modules are a minority, yet I see dozens of them popping up all over the place and there's no real documentation. So basically, you use execute() for the default output of the admin page when you go to it, or maybe use it as ajax handler for something on JS side of your module. That part doesn't allow urlSegments. Segment one added your admin url, must be defined by a executeYoursegment() as we already know by now So those most likely build the "subpages" of your admin page, if really needed. And you could expand using urlSegments or url params.
    1 point
  33. I think the last time this came up someone mentioned there is a unique user ID in Active Directory that would be worth storing (objectGUID). My scenario is if someone gets married and you remember to change it in AD you might not remember to change it in other places. Therefore they would be treated as a new user in this module. It would be amazing if when it can't find the user it checks details via LDAP but then also checks the objectGUID against the PW database and update name and other details accordingly. Just a thought, but I know how annoying it can be the more pieces of software you have to remember to change logins across. Even armed with a checklist it can take more time than it needs to EDIT: This comment on PHP.net might be of interest: http://php.net/manual/en/function.ldap-get-values-len.php#111899
    1 point
  34. I think you understood Soma but he will speak for himself. As for my bit, have a look at my ProcessBlog module. I use both ___execute() and wire('input')->urlSegment1 (your $this....etc). ___execute(), in a sense, gives you 'virtual pages view'. They don't really exist but are created on the fly on view (if that makes sense). In my case (in Blog), in the method blogMenu(), I use urlSegment1 to set the css class for the active ___execute() page, i.e. what the user is currently viewing. It's basically grabbing a 'GET' query string (in a loose sense)...Otherwise, there was no other way to know what the active page was given that they don't actually exist. ... So, if you want a viewable 'page' in your ProcessModule, use ___executeSomething()...urlSegment1 just gives you the 'name' (something) of that virtual page... my 2p...
    1 point
  35. Other than that, try stripping out things like canvas and calls to schema.org and generally simplify it down and see what that achieves. I sometimes kick out my headers and footers as well so I am not adding JS and CSS to the problem - doesn't matter what it looks like, just how fast it loads at that point. Then start adding bits back ...
    1 point
  36. Thanks Adrian! Now I know what was going on. I have had this code, what was working before: $p = $this->pages->get(3)->children()->get('name=image-crop'); and then I have broken it at the children() part, because in the install-routine when the adminPage gets created, I have set the page to hidden. So a simple 'include=all' or 'include=hidden' as selector for the children() will make it work again. Hhm, I love it when I get to know why / how things do work the way they do. PS: yes it seems there is much similarity between our works at the moment.
    1 point
  37. But I don't think you want to call them individually - what if you decide to add a 4th image at some point - then you'd need to change your code to add: ->eq(3). Best bet is to do what kongondo suggested: foreach($page->slider1 as $img){ echo "<div class='item'><img src='{$img->url}' /></div>"; }
    1 point
  38. I am also struggling with this a little at the moment. If the parent has requires and installs set to the child module I can install the parent and have the child install. Also it prevents me from uninstalling the child directly (which I want), but when I go to uninstall the parent, it can't uninstall the child automatically because the parent needs it at the point of uninstall still. If I remove the requires from the parent, then the parent can uninstall the child, but then someone could also manually uninstall the child, which I would like to prevent. Is this possible?
    1 point
  39. I hope it is still being maintained, it's a really awesome module that make things very easy.
    1 point
  40. http://ht-heizelemente.de => An error has occurred, there is no configuration file for the current domain. {13:50 gmt} cookie wall, visitor has no choice to visit the site with or without cookies.
    1 point
  41. Soma, that won't work because that's just a string comparison. You'd need to use PHP's version_compare() function instead. There is also $modules->versionCompare($currentVersion, $requiredVersion, $operator); that achieves the same thing, but accepts version numbers as either strings or integers (and you can mix and match if needed). Of course you could pass through the version for PW or any module to JS anywhere you wanted, via $config->js() or in a data attribute of some markup, etc. I think the need is likely rare though, since requests originate on the PHP side and any version checking is usually better done there. No changes to the permission property, other than that it can now be used on any module type (not limited to just Process modules anymore). Usage is the same as before and it specifies the single permission name needed for PW to execute the module, (i.e. 'permission' => 'widget-edit'). Though there is a 'permissions' property (in 2.5) where you can specify permissions that you want PW to automatically install with your module (and likewise uninstall), i.e. 'permissions' => array(' 'widget-edit' => 'Edit a widget', 'widget-add' => 'Add a widget' ) Your module is responsible for permission checking, outside of the one permission you may have specified in order for the module to be executed. For instance, if you had an executeAdd() method in your module, you might like to do a if(!$this->user->hasPermission('widget-add')) before rendering an "add" button, as well as at the top of your executeAdd() method. Yes, you can throw an exception from either install() or uninstall() to cancel the operation. Though in your scenario, I would usually make the Fieldtype module the parent one (rather than the Process), since it is the one module in your set that may be externally linked (i.e. via fields that are using it).
    1 point
  42. thank you! i knew that has to be a little processwire trick that i didn't know yet
    1 point
  43. I don't think there is a currently a module that does this but you can easily build a simple Process Module to do this. It can either be based on Batcher (i..e. copy its code, rename it and customise to your needs) or see how similar things are done in Blog (see the posts dashboard - both quick post and bulk actions). Start building something and the forum will be here to help you Btw, are you tagging with existing tags or creating tags on the fly or both?
    1 point
  44. Finnish web hotel with ProcessWire preinstalled: http://www.zerodistance.fi/palvelut/webhotelli-pw.php
    1 point
  45. Just submitted PW here for tag CMS: http://oozled.com/resources/cms
    1 point
  46. ProcessWire and ryan's famous Post 144 is mentioned towards the end (~58:10) of #135 of Chris Coyier's ShopTalkShow Podcast: http://shoptalkshow.com/episodes/135-bastian-allgeier/. Allgeier, who runs Kirby CMS, totally agrees with Ryan when it comes to a system's ability "teach people how to fish" vs out-of-the-box.
    1 point
  47. The disadvantage with uniqid() is that its output is predictable since the value returned is based on the current timestamp. So on the surface, it seems there's possibility for that to be exploited, although it might be challenging. The password generation I put in the example above is based all around random characters, which aren't predictable other than the set which they come from (a-z2-9) and the length (between 9 and 12). I think this is pretty strong. However, the security of it could be increased by adding more to the set of possible characters (punctuation, upper/lower, etc.) and increasing the possible length range, like up to 30 characters or something. I opted to limit the character set and exclude the letters that are easily confused with each other, like "o O 0" and "i I l 1", just in case people are hand-typing (rather than copy/pasting)… less support burden. Another thing I might add to the code would be to make it only work with users of a certain role. But that would be pretty site-specific, so left it out here.
    1 point
  48. I recently had to setup front-end system to handle logins, password resets and changing passwords, so here's about how it was done. This should be functional code, but consider it pseudocode as you may need to make minor adjustments here and there. Please let me know if anything that doesn't compile and I'll correct it here. The template approach used here is the one I most often use, which is that the templates may generate output, but not echo it. Instead, they stuff any generated output into a variable ($page->body in this case). Then the main.php template is included at the end, and it handles sending the output. This 'main' template approach is preferable to separate head/foot includes when dealing with login stuff, because we can start sessions and do redirects before any output is actually sent. For a simple example of a main template, see the end of this post. 1. In Admin > Setup > Fields, create a new text field called 'tmp_pass' and add it to the 'user' template. This will enable us to keep track of a temporary, randomly generated password for the user, when they request a password reset. 2a. Create a new template file called reset-pass.php that has the following: /site/templates/reset-pass.php $showForm = true; $email = $sanitizer->email($input->post->email); if($email) { $u = $users->get("email=$email"); if($u->id) { // generate a random, temporary password $pass = ''; $chars = 'abcdefghjkmnopqrstuvwxyz23456789'; // add more as you see fit $length = mt_rand(9,12); // password between 9 and 12 characters for($n = 0; $n < $length; $n++) $pass .= $chars[mt_rand(0, strlen($chars)-1)]; $u->of(false); $u->tmp_pass = $pass; // populate a temporary pass to their profile $u->save(); $u->of(true); $message = "Your temporary password on our web site is: $pass\n"; $message .= "Please change it after you login."; mail($u->email, "Password reset", $message, "From: noreply@{$config->httpHost}"); $page->body = "<p>An email has been dispatched to you with further instructions.</p>"; $showForm = false; } else { $page->body = "<p>Sorry, account doesn't exist or doesn't have an email.</p>"; } } if($showForm) $page->body .= " <h2>Reset your password</h2> <form action='./' method='post'> <label>E-Mail <input type='email' name='email'></label> <input type='submit'> </form> "; // include the main HTML/markup template that outputs at least $page->body in an HTML document include('./main.php'); 2b. Create a page called /reset-pass/ that uses the above template. 3a. Create a login.php template. This is identical to other examples you may have seen, but with one major difference: it supports our password reset capability, where the user may login with a temporary password, when present. When successfully logging in with tmp_pass, the real password is changed to tmp_pass. Upon any successful authentication tmp_pass is cleared out for security. /site/templates/login.php if($user->isLoggedin()) $session->redirect('/profile/'); if($input->post->username && $input->post->pass) { $username = $sanitizer->username($input->post->username); $pass = $input->post->pass; $u = $users->get($username); if($u->id && $u->tmp_pass && $u->tmp_pass === $pass) { // user logging in with tmp_pass, so change it to be their real pass $u->of(false); $u->pass = $u->tmp_pass; $u->save(); $u->of(true); } $u = $session->login($username, $pass); if($u) { // user is logged in, get rid of tmp_pass $u->of(false); $u->tmp_pass = ''; $u->save(); // now redirect to the profile edit page $session->redirect('/profile/'); } } // present the login form $headline = $input->post->username ? "Login failed" : "Please login"; $page->body = " <h2>$headline</h2> <form action='./' method='post'> <p> <label>Username <input type='text' name='username'></label> <label>Password <input type='password' name='pass'></label> </p> <input type='submit'> </form> <p><a href='/reset-pass/'>Forgot your password?</a></p> "; include("./main.php"); // main markup template 3b. Create a /login/ page that uses the above template. 4a. Build a profile editing template that at least lets them change their password (but take it further if you want): /site/templates/profile.php // if user isn't logged in, then we pretend this page doesn't exist if(!$user->isLoggedin()) throw new Wire404Exception(); // check if they submitted a password change $pass = $input->post->pass; if($pass) { if(strlen($pass) < 6) { $page->body .= "<p>New password must be 6+ characters</p>"; } else if($pass !== $input->post->pass_confirm) { $page->body .= "<p>Passwords do not match</p>"; } else { $user->of(false); $user->pass = $pass; $user->save(); $user->of(true); $page->body .= "<p>Your password has been changed.</p>"; } } // display a password change form $page->body .= " <h2>Change password</h2> <form action='./' method='post'> <p> <label>New Password <input type='password' name='pass'></label><br> <label>New Password (confirm) <input type='password' name='pass_confirm'></label> </p> <input type='submit'> </form> <p><a href='/logout/'>Logout</a></p> "; include("./main.php"); 4b. Create a page called /profile/ that uses the template above. 5. Just to be complete, make a logout.php template and create a page called /logout/ that uses it. /site/templates/logout.php if($user->isLoggedin()) $session->logout(); $session->redirect('/'); 6. The above templates include main.php at the end. This should just be an HTML document that outputs your site's markup, like a separate head.inc or foot.inc would do, except that it's all in one file and called after the output is generated, and we leave the job of sending the output to main.php. An example of the simplest possible main.php would be: /site/templates/main.php <html> <head> <title><?=$page->title?></title> </head> <body> <?=$page->body?> </body> </html>
    1 point
  49. Man, that was so obvious, I feel like a fool. Thanks, apeisa. As always, PW is simpler than you'll assume it is.
    1 point
×
×
  • Create New...