Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/21/2013 in all areas

  1. This hasn't been asked, but wanted to cover how the permissions and publish workflow work on the site. It has a very simple, though nice setup, where authors can submit new posts but can't edit already published posts, nor can they edit unpublished posts by other authors. It enables Mike to have full control over any content that gets published on the site, while still allowing easy submission and edits for the authors. Post workflow All of the authors have a role called "author" with page-edit permission. On the "post" template, the boxes for "edit" and "create" are checked for this "author" role. This site also makes use of the page-publish permission, which is an optional one in ProcessWire that you can add just by creating a new permission and naming it "page-publish". Once present, it modifies the behavior of the usual page-edit permission, so that one must also have page-publish in order to publish pages or edit already published pages. The "author" role does not have page-publish permission. As a result, authors on the site can submit posts but can't publish them. Nor can they edit already published posts. In this manner, Mike has final say on anything that gets posted to the site. Post ownership The default behavior in ProcessWire is that the Role settings control all access... meaning all users with role "author" would be able to do the same things, on the same pages. In this case, we don't want one author to be able to edit an unpublished/pending post created by another author. This was easily accomplished by adding a hook to /site/templates/admin.php: /** * Prevent users from being able to edit pages created by other users of the same role * * This basically enforces an 'owner' for pages * */ wire()->addHookAfter('Page::editable', function($event) { if(!$event->return) return; // already determined user has no access if(wire('user')->isSuperuser()) return; // superuser always allowed $page = $event->object; // if user that created the page is not the current user, don't give them access if($page->createdUser->id != wire('user')->id) $event->return = false; }); Planned workflow improvements Currently an author has to let Mike know "hey my article is ready to be published, can you take a look?". This is done by email, I'm assuming. An addition I'd like to make is to add a Page reference field called "publish_status" where the author can select from: DRAFT: This is a work in progress (default) PUBLISH: Ready for review and publishing CHANGE: Changes requested - see editor notes DELETE: Request deletion Beyond that, there is also an "editor_notes" text field that only appears in the admin. It's a place where Mike and the author can communicate, if necessary, about the publish status. This editor_notes field doesn't appear on the front-end of the site. All this can be done in ProcessWire just by creating a new field and adding these as selectable page references. That's easy enough, but I want to make it so that it notifies both Mike (the reviewer) and the author by email, every time there is a change in publish status or to the editor_notes. This will be done via another hook in the /site/templates/admin.php: wire()->addHookAfter('Page::saveReady', function($event) { // get the page about to be saved $page = $event->arguments(0); // if this isn't a post, don't continue if($page->template != 'post' || !$page->id) return; // if this post wasn't made by an "author" don't continue if(!$page->createdUser->hasRole('author')) return; $subject = ''; $message = ''; if($page->isChanged('publish_status') || $page->isChanged('editor_notes')) { // the publish status or editor notes have changed $subject = "CMSCritic post publish status"; $notes = $page->isChanged('editor_notes') ? "Notes: $page->editor_notes" : ""; $message = " Title: $page->title\n URL: $page->httpUrl\n Status: {$page->publish_status->title}\n $notes "; } else if($page->isChanged('status') && !$page->is(Page::statusUnpublished)) { // page was just published $subject = "CMSCritic post published"; $message = "The post $page->httpUrl has been published!"; } if($message) { $reviewer = wire('users')->get('mike'); $author = $page->createdUser; mail("$reviewer->email, $author->email", $subject, $message); $this->message("Email sent: $subject"); } }); Mike, if you are reading this, does this sound useful to you?
    4 points
  2. Put it on Githhub again..https://github.com/SiNNuT/countries/ Not actively maintained, but i don't think there were a lot of new countries the last year.
    2 points
  3. That's the intention: to limit voting to people that are qualified to answer. People that know and are enthusiastic about a product take pride in being able to answer questions like this. I'm thinking that most in our community would be very enthusiastic about answering these questions, and I'm guessing the same goes for other products that people are enthusiastic about. On the other hand, my Mom's mothers club, Soma's high school buddies, Diogo's cousins and Antti's neighbors that arrive there from Facebook with the best of intentions to support ProcessWire (even if they don't know what it is), will get scared off, or at least answer honestly, because they don't understand the questions. IMO, that's a good thing that encourages quality over quantity (with apologies to my mom, Soma, Diogo and Antti's Facebook friends and of course the mothers club). There's also the selfish aspect: I think ProcessWire can compete with much more widely known projects like MODX and Concrete5 when dealing with qualified users of the product. But once bigger projects get their casual social networks involved, we would be outgunned. And the easier the questions are to answer, the more outgunned we might be. I'm guessing the most controversial question I mentioned is probably the one asking for a URL to a site running in the CMS. While that would be a great qualifier, I think you'd still derive benefits in quality, without much loss in quantity, from any questions that ask about the user's experience with the CMS: 1. How many sites have you used with this CMS? [ ] 0 [ ] 1 [ ] 2-3 [ ] More than 3 2. How have you used the CMS? [ ] As a web developer [ ] As a web designer [ ] As an editor (you edit content using the CMS) [ ] As a user (applies to forum software only) [ ] I have not used it 3. What is your favorite feature of this CMS? [Text field] 4. Enter your email address You'd accept the submission, but ultimately exclude the vote from counting if any of these conditions are met: 1. They answer "0" to question 1. 2. They answer "I have not used it" to question 2. 3. They answer "I don't know" or some other meaningless response to question 3. 4. Their email address or IP address matches one for a vote already taken. As a bonus, you'd have the option (if you wanted it) of filtering results by user type (web designer, developer, etc.), experience level with the CMS, and the ability to highlight the most liked features of some products. Meaning, questions like these aren't just about qualification, but about giving you more options with filters and views into the data, now or in the future. These are all just ideas and my opinion only. You've of course got my support and enthusiasm regardless of what direction you go with the voting.
    2 points
  4. echo html_entity_decode(__('you.text w <blink>htmls</blink>'));
    2 points
  5. 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.
    1 point
  6. TextformatterImageInterceptor ( Textformatter module ) Let editors use WYSIWYG images, but let you control the image size, aspect ratio & behaviour. How to install Copy the TextformatterImageInterceptor.module file to your /site/modules/ directory (or place it in /site/modules/TextformatterImageInterceptor/). Click check for new modules in ProcessWire Admin Modules screen. Click install for the module labeled: "Image Interceptor". Go to the module config screen and set the settings you wish. How to use Edit your body field in Setup > Fields (or whatever field(s) you will be placing controlled images in). On the details tab, find the Text Formatters field and select "Image Interceptor". Save.About the settings Render Inline styles If checked, some inline styles are added to the image.High Density Double the pixel width of an image if the percentage is not set. (fixed image size)Default there are settings for landscape & portrait images. Squared images will inherit all settings belonging to portrait settings and there's a way to escape the default settings. But before we dive deeper in tagged sets I want to spread some light on the landscape/portrait settings. All images portrait/landscape wil get the class name .default. ps, All images including tagged set images get the image orientation as class (.landscape / .portrtait) Percentage The width of the image in percentage. This setting makes the image responsive or if left blank the image wil be fixed size. Images receive a .responsive and a .p-50 class (where 50 is the width in percentage) Width The width of the image in pixels. So the width of the image in percentage and the pixel width combined wil be the key to pixel desity. Alignment There are 5 different ways to align an image. left, center, right, inherit (inherits from the WYSIWYG editor) and not aligned. If render inline styles is checked the aligment wil be set directly in the inline style of the image. Alignment classes wil be added to the image. Aspect Ratio (cropping) if an aspect ratio is given, the image will be cropped to the given ratio. If you type 2:1 in the landscape settings. Images 800 pixels wide, will be croped to a 800x400 image. The image gets the following classes: .cropped and .crop-2x1 Image Captions Type here your class name(s) for the caption. When a class name is provided and an image has a description, the image is wrapped (if not already) and *has-* is set in front of the class name(s). For the caption a div is created with the class name(s) and the image description as text. Next to these settings. You can give custom classes to images. This way you can give it framework specific classes for example. And you're allowed to wrap the images with custom HTML. (Some frameworks needs additional HTML to make images more fancy) Then additional styles could be added to images if render inline styles is checked. Tagged sets Tagged sets are an image tag followed by settings specific for images with that tag. To enable tagged sets, the image field need "Use Tags?" to be checked. Go to setup, then fields go to your image field and under the details tab check "Use Tags?". Taged sets are a good way to escape the default image behaviour. Say you have a bunch of nicely ordered images on the page, but you want to show a company logo on 150px floated left. With tagged sets it's no problem. type: (logo 150px left) on one line and you've created your first tagged set. (don't forget to tag the image to) If you want captions for a tagged set, keep in mind that captions need at least 1 class. The format to enter: caption.class-name. For an image wrapper we use the same rules. The only difference is we start typing wrapper followed by class names starting with a dot. example: wrapper.logo.stand-out. You can have a multitude of sets, every set on it's own line. Every set needs at least a tag-name and a pixel width. Note: If you use a wrapper or captions (wrapper will be created if none is set), the inline styles and specific width & alignment classes will be set to the wrapper and removed from the image. This way no duplication of styles wil take place. github modules directory
    1 point
  7. Ryan was kind enough to agree to answer some questions about himself and about ProcessWire for an interview which I've posted over on my blog at http://codingpad.maryspad.com/2013/07/19/interview-with-ryan-cramer-processwire-cms-founder-and-lead-developer/ I think it's a pretty good read and quite informative and hope it brings lots more exposure to PW and how awesome it is! Many thanks Ryan, you rock!!
    1 point
  8. All: If you saw some of my recent postings where I was trying to solve the problem of running a query as a field, I have solved it. I started with Hanna text, but that didn't quite get me all the way. Then I tried just a Concat field, and that didn't get me all the way. I modified the Concat fieldtype for my solution. I had a need to dynamically pull Pages that were cross-referenced back: Product as a Page Photo Pages with a multi-Page Select field that referenced Product (A photo could represent 1+ Products) I wanted a ->photos field from Product that was updated dynamically according to what Photo entries were currently in place, and I didn't want copy/pasted code, and I wanted the selectors to be easily modifiable from the admin screens. Usage is faily simple: 1: Install as a normal module 2: Create a field as a PagesSelectorQuery type 3: On the field details, enter your selector string, ie: template=my_template,select_page_field=$page 4: Add your field to whichever templates. 5: Access the PageArray results like you would any other $page->field I hope you find it useful, at the very least as an exercise in my madness. Thanks again for all the help this community has provided. EDIT: Added to GitHub: https://github.com/alevinetx/processwire-modules/blob/master/FieldtypePagesSelectorQuery.module And Module's page: http://modules.processwire.com/modules/fieldtype-pages-selector-query/ FieldtypePagesSelectorQuery.module
    1 point
  9. Yes, check the password length for mysql. SELECT user, Length(`Password`) FROM `mysql`.`user`; SHould be a 41 character field. If not see the link below. http://blog.mixu.net/2010/06/06/quick-tip-how-to-fix-mysqlnd-cannot-connect-to-mysql-4-1-using-old-authentication-onphp5-3/
    1 point
  10. Hi Horst! Thanks so much for the reply and looking into this! I've tried your code Horst and guess what... it works! Awesome stuff! Your one clever guy! Using Google... ich danke Ihnen sehr
    1 point
  11. You don't have to apologise to my facebook friends, unless I can have the friends without having an account... You can apologise to my cousins though
    1 point
  12. For content you should not use this method, but multilang fields instead. On front end tokens are fine for some mostly static stuff like button labels ie. "search" etc.
    1 point
  13. @WillyC I did not know about html_entity_decode(), and in fact is solves my problem for now: <p> <?php $t = "We love to <span class='highlight'>highlight</span> so that it <span class='highlight'> stands out</span>."; $t = __($t); echo html_entity_decode($t, ENT_QUOTES, 'UTF-8'); ?></p> main.css .highlight { font-weight: 600; color: red; } The string will be output with the words 'highlight' and 'stands out' shown in bold red. Thanks a lot for this tip! At everyone: Soma mentioned that when using __("text"), everytime I change the text, the translations needed to be updated, too. I haven't started doing any translations, but I know that I often tweak text here and there, even if I intially thought it was 'final'. I certainly don't want the translaters have to redo their translation every time I do such a tweak. Is there a way to deal with edits to the main language text without effecting its translations? Cheers, Stefan
    1 point
  14. Hi Hendrik, Welcome to PW and the forums! Normally, if it has the right setup, PW will rename site-default to site after install. Do you mean to say you have both "site-default" and "site"? Rename "site-default" to "site" and get rid of the other "site" folder. Create your templates files inside "site". Note, you can also create templates without template files but that's a bit advanced for you right now Edit: Martijn was faster
    1 point
  15. Hey Ryan, that is exactly what it is doing for me right now too. I can only assume that right now I need more sleep, but I'll keep an eye on it.
    1 point
  16. According to http://dev.mysql.com/doc/refman/5.6/en/blob.html, BLOB and TEXT fields cannot have a default value.
    1 point
  17. Hi Soma, That is a very interesting option. It's just that I haven't dealt with translations before, and therefore am not quite sure how to proceed. Could you post a link to an introduction of such translation system? Cheers, Stefan
    1 point
  18. Why not use a simple language file with php vars or a page with language text fields? The translation in PW isn't really suited for such forrmatted text in front end. Theres too many restrictions and the default text is like a key means once you change a typo or word you have to reenter all translations again.
    1 point
  19. Just add something like this to the top of your events index page. You could compartmentalize this into a LazyCron call, but for such a simple thing it's really not necessary. $events = $pages->find('parent=/events/, date<"-3 months"'); foreach($events as $event) { $event->of(false); $event->addStatus(Page::statusUnpublished); $event->save(); } Btw, when testing something out like this, always comment out the $event->save(); the first time and take a look at what pages get affected by echoing them rather than saving them, the first time around. i.e. // $event->save(); echo "<p>Unpublishing: $event->url</p>"; Once confirmed that it is behaving the way you want, then remove the echo and uncomment your save();
    1 point
  20. Awesome Nikola! I really like this module. Just a few suggestions: The module should not extend Process since it's not an admin process. Instead it should extend WireData. The module should not be autoload since it is loaded from an API call instead. Ideally the module would be called MarkupWeather or MarkupYahooWeather, since the "Markup" prefix is recommended for all markup-generation modules. Please add it to the modules directory as soon as you get the chance. It's a lot simpler to do now, as the modules directory pulls most stuff right from your GitHub page.
    1 point
  21. ImageMinSize Module Already there since a couple months, I figured I'd finally add it to the repository. What it does ImageMinSize module allows you to define a minimum width and or height an image needs to have when uploading. This is same as the already existing maximum image size setting, just on the other end. You can set the max and min width and height setting to the same to restrict uploaded images to a specific size. If the requirements aren't met it will delete the image and show an error. After installing the module you'll be presented with the additional minimum width and height setting in the fields input configuration. Currently on github https://github.com/somatonic/ImageMinSize On modules repository (in approval state) http://modules.processwire.com/modules/image-min-size/ This module was getting started because of this thread: http://processwire.com/talk/topic/3476-fixed-image-size/?hl=imageminsize#entry34110
    1 point
  22. Thanks Ryan! Haven't really thought about that, so thanks for the heads up! I changed the keys and also added support for a volume property that will get calculated everytime a dimension changes and stored to DB. So it can be used for convenience if needed to get the volume, and also use it in selectors. I updated the module and readme to reflect that change, along with some cleanup and coments. If you happen to already have the module installed, I recommend to reinstall the module for the updated index in db tables.
    1 point
  23. Ohh I just got an idea for a module. What if you have a gallery type page you upload the images as usual to an images field. Then when saving the page there would be children created for each image and the ones removed from the gallery page. This would be very simple few lines of code. Sorry to hijack your thread. Nothing against the method to have one images field you store a gallery. If theres no metadata needed with no multilang and so on it is a pretty good and simple way to a simple gallery. I use it myself too.
    1 point
  24. this another language.swatch work wit any num.languagees new localUrl func echo "<ul>"; foreach($languages as $language) { $class="$language"=="$user->language" ? "active" : ""; $url=$page->localUrl($language); echo "<li class=\"$class\"><a href=\"$url\">$language->title</a></li>"; } echo "</ul>"
    1 point
  25. Greetings, Just wanted to say thanks for this discussion. I'm still new to ProcessWire, and I had a similar question. The fact that such a discussion can take place here so naturally is one of the many reasons I find ProcessWire so good. What you are all discussing here is what one could call "good general practices" for deploying any site. However, in other CMSs, when you ask such a question, you get the general information then you have to go further and say, "OK, now how do I do this in [name] CMS?" With ProcessWire, what I really like is that the answer is simply the answer, and not "Here's how you need to do it in ProcessWire." This principle seems to extend all the way through ProcessWire -- from templates to JQuery, and more. It's one of the principles that I find very appealing about the system Thanks, Matthew
    1 point
  26. 1 point
  27. Absolutely! Here is a simple, but functional example for both login and logout templates. You would want to replace the markup with your own markup or includes. Likewise you'd want to change the redirects to redirect to whatever page you want them to go to after completing a login. /site/templates/login.php: <?php if($user->isLoggedin()) { // user is already logged in, so they don't need to be here $session->redirect("/somewhere/"); } // check for login before outputting markup if($input->post->user && $input->post->pass) { $user = $sanitizer->username($input->post->user); $pass = $input->post->pass; if($session->login($user, $pass)) { // login successful $session->redirect("/somewhere/"); } } ?> <html> <head> <title>Login</title> </head> <body> <form action='./' method='post'> <?php if($input->post->user) echo "<h2 class='error'>Login failed</h2>"; ?> <p><label>User <input type='text' name='user' /></label></p> <p><label>Password <input type='password' name='pass' /></label></p> <p><input type='submit' name='submit' value='Login' /></p> </form> </body> </html> /site/templates/logout.php: <?php $session->logout(); ?> <html> <head> <title>Logout</title> </head> <body> <h1>You have logged out</h1> </body> </html>
    1 point
×
×
  • Create New...