Leaderboard
Popular Content
Showing content with the highest reputation on 04/30/2013 in all areas
-
A little bit of new fun stuff on the 2.3 dev branch: Anonymous functions and hooks You can now use PHP 5.3+ anonymous functions when attaching hooks. All the syntax below will work either from your template files, modules, or any Wire derived class. If using outside of template files or Wire-derived classes, then replace $this with wire(). Though anywhere that you can use $this you can also use wire(), so syntax is also a matter of preference. Example: Add a "hello()" function to all pages that returns "Hello World!": $this->addHook('Page::hello', function($event) { $event->return = "Hello World!"; }); Result: echo $anyPage->hello(); // outputs: Hello World! Example: Add a 'hi' property to all Users that contains the value "Hi [their name]!". $this->addHookProperty('User::hi', function($event) { $user = $event->object; $event->return = "Hi $user->name!"; }); Result: echo $user->hi; // outputs: Hi Ryan! Example: Add a grandparent() function to all pages. $this->addHook('Page::grandparent', function($event) { $page = $event->object; $event->return = $page->parent->parent; }); Result: $myPage = $pages->get('/about/news/categories/sports/'); echo $myPage->grandparent()->url; // outputs: /about/news/ Example: Save a message to a log file for each new page that is added. $pages->addHookAfter('added', function($event) { $page = $event->arguments(0); $this->message("Added new page: $page->path", true); }); Result: The message is added to log file /site/assets/logs/messages.txt when a new page is added. Example: Add a 'createdString' property to all Page objects that is the same as $page->created except that it outputs in a human readable format rather than a unix timestamp: $this->addHookProperty('Page::createdString', function($event) { $page = $event->object; $event->return = date('Y-m-d H:i:s', $page->created); }); Result: echo $page->createdString; // outputs 2013-04-30 03:05:00 This just touches on the possibilities with some overly simple examples. But you can use these anywhere you'd use any other hooks: from within modules, templates, or anywhere in ProcessWire. I think that the anonymous function syntax is particularly convenient within templates, when you can define your own helper functions in your head.inc or init.php or whatever file you have starting your templates. Don't forget you can add stuff in /site/templates/admin.php too in order to hook into things that happen during administration. Error and message logs ProcessWire has always maintained logs, but I'm guessing that most don't know how to write to them. So I setup a simpler syntax for you to save things to PW's system log files: $this->message("This text will be saved to /site/assets/logs/messages.txt", true); $this->error("This text will be saved to /site/assets/logs/errors.txt", true); This is the same as these functions worked before, except for the second "true" argument, which tells it to write to the log file. From the admin side, it'll still display these messages interactively. If you only want it to log and not display the messages in the admin, then replace the "true" with "Notice::logOnly". Though if you are doing this from templates, then you don't need to consider that since templates (other than the admin template) don't typically output ProcessWire's notices. --- Edit: I changed the wire() syntax in the examples to $this. Though either works from template files and modules, but I think $this syntax is more familiar to most.10 points
-
7 points
-
"Recommended by Mr. Log Himself", it seems. We're not getting off-topic, are we?3 points
-
"Hook*r, directly from the creator of After Shave Actions".. yeah, that sounds just about right3 points
-
..and now I can let go of trying to come up with a less questionable name for a planned module listing active hooks! Working title was Hook*r.3 points
-
No. MySQL can execute hundreds of well optimized queries faster than one unoptimized one. And MySQL can often execute lots of simple queries faster than 1 complex one. ProcessWire takes advantage of this where it can. Query counting isn't useful anymore (if it ever was).2 points
-
You have to consider XSS anywhere that the [untrusted] user can enter content that will be saved and echoed back to other users. In a default ProcessWire installation with no 3rd party modules, there aren't many places to consider this. The admin is designed for trusted users only. The comments module is the only thing that accepts and stores untrusted user input. It won't store markup in comments. It filters by stripping markup before storing a comment, and by entity encoding output when displaying a comment. Also consider that ProcessWire is designed to let you do what you want to do. If you want to create a text/textarea field that lets you enter script tags, then ProcessWire won't stop you. There are plenty of legitimate uses for such things. There simply isn't anywhere that an untrusted user can enter markup. But HTMLPurifier might have a place in your individual installation. If you are dealing with untrusted user input and allowing markup (HTML) then HTMLPurifier is essential. We have an HTMLPurifier module, ready to use. Content is validated and sanitized server-side, not client side. Though on text-based fields entered in the admin, we make no assumptions about what you are using them for. Even scripts are a legitimate use case (consider video embedding, etc.). Some Inputfields may have client-side validation built-in to do one thing or another (TinyMCE is an example). Though ProcessWire doesn't care about client side validation. What sanitization/validation takes place depends entirely upon the Fieldtype. From the admin side, the text-based fieldtypes are designed to contain any text, including any kind of markup. This is one reason why ProcessWire's admin is focused on trusted users only. While I don't recommend using PW's admin with untrusted users, there may be situations where you have "mostly" trusted users. In such cases, you may want to avoid things like rich text fields and focus on LML-based text formatters (safe ones, like Textile Restricted or BBCode) or even HTML Purifier. Our new CKEditor module actually does use the HTML Purifier for inline mode, since inline mode markup is not entity-encoded when presented in the admin. This is a consideration for any text fields that you don't want to support markup. Such fields might include your 'title' and 'summary' fields, but would exclude something like your 'body' field, which is designed specifically to contain markup. ProcessWire uses a type of modules called Textformatters. For any field that you want to have runtime output formatting, you can add an HTML Entities (or other types) Textformatter from Setup > Fields > [your field] > Details. This is only applicable to text-based fields. For entity encoding output yourself, use $sanitizer->entities($str). Generally you wouldn't ever use this on your managed content stored in PW. Instead, you would use it when echoing back something that the user entered, like search query: $q = $input->get->q; if($q) { $results = $pages->find("body%=" . $sanitizer->selectorValue($q)); echo "<h2>You searched for: " . $sanitizer->entities($q) . "</h2>"; if(count($results)) echo $results->render(); else echo "<p>Sorry, no results were found.</p>"; } ProcessWire's API does not use SQL queries, unless you choose to use the $db variable. So if you want to execute SQL queries, then you should follow best practices towards avoiding SQL injection. However, there are very few scenarios where any of us use SQL in developing websites or apps in ProcessWire, so it's generally a non-issue. What you do have to consider instead is selector injection, even if it's not nearly as potentially dangerous as SQL injection. So that's why we have the $sanitizer->selectorValue(); function. Note the use of it in the code segment above. Yes, all ProcessWire forms are CSRF protected.2 points
-
Regarding moving assets (as in static site files, JS and images etc.) outside /site/: Keeping everything "site-specific" within /site/ can make upgrading ProcessWire slightly easier and enables you to move all site-specific files to another server / PW installation etc. without needing to wonder which files were / are part of PW and which belong to this specific site. This is also how (and why) modules such as Site Profile Exporter work; they simply copy (most) content of /site/ folder and leave everything else intact. So, short answer is "yes, you can do it." But that doesn't necessarily mean that you should do it2 points
-
You should look up XAMPP instructions for e.g. Joomla on Youtube. There are great simple video tutorials that show you how to set up a database and run your PHP app. I think you'd be able to follow along with ProcessWire files & setup just fine.2 points
-
So, - that thing with the Titles (sanitizing but leave spaces, etc) seams to be solved. Also basic stream support is added. The output to the frontend is only a simple menu and information about current page. It's made for coders You may have a look to output (it's a bit like var_dump) and the code in the 2 Templatefiles. That's intended as starting point for your own Frontend creation. There is an own caching mechanism with the LocalAudioFiles-module. It caches the menus and the DB-infos. It refreshes them when DB gets modified or you may permanently disable caching in the modules page. Here are the latest screencast: https://youtu.be/qeT5s013GUE and here without audio for the german audience https://youtu.be/MefyBCDDXrs I want upload the first site profile, but have got an error when importing (Can't save page 0: /genre//: It has empty 'name' field). So I first want to fix that and upload siteprofile after that. (Maybe tomorrow evening)2 points
-
@kongondo, for me there is a big difference between a php framework and a css framework, but this is maybe because I am a designer, and although I worry about the server side, the website design is my ultimate goal. Anyway, php is hidden, and if a framework gives you enough flexibility to achieve what you want while removing a lot of work from you, that's great! PW gives us exactly that, but honestly, I couldn't care less about how I achieve things in php, I just want things to work, and have a professional looking backend for my clients. As a designer, the frontend is what I'm selling to my clients and where I really want to make a difference. I don't want to start designing thinking of an imposed grid. I want to use a grid if it fits my design, but not to use it if it doesn't. Of course I keep some snippets of code, but I don't get too attached to them because every time I need to do something someone came up with an even nicer solution already, and it really doesn't take much time to look for things when you need. As for jQuery, I wouldn' also compare it with css frameworks, because it has more to do with how you write javascript then what you do with it. IMO the fair comparison would be with be with jQuery UI for instance. Anyway, I'm glad the frameworks are there, and that they make things easier when you need, I just don't think that it is possible that you choose one and become really good at it without becoming somehow dependent on the tool and without it influencing and limiting your designs. In the end, all comes to what you want to offer with your work, and I'm not saying that some choices are more valid than others.2 points
-
I'm embarrassed to admit that I send them myself, using a script I wrote more than a decade ago. It's always worked fine, so I've just stuck with it. But I agree with the guys that say it's better to use a service. Someday I will take that advice myself too. But if you want to use what I'm using, here you go… First you'll need a text file with your subscribers in it. 1 email address per line. It can be only a few, or it can be thousands. subscribers.txt bob@email.com jim@bigcompany.com mike@little-org.com Now you'll need the email content. You'll want 1 HTML file and 1 text file. Both should have the same content: template.html <html> <head> <title>test email</title> </head> <body> <h1>Test</h1> <p>This is a test email</p> </body> </html> template.txt TEST This is a test email email.php Place this PHP file in the same directory as the above files. Edit the DEFINEs at the top as necessary. I apologize in advance for this rather awful email solution, but hey it works, and that's why I haven't bothered to rewrite it in 10 years. To run, place the files on a web server and then load in your browser. It should start emailing immediately, once every 3 seconds. If you are sending thousands, then it might take several hours. But because it sends slow, it never seems to caught up in any filters. <?php /** * GhettoMailer v1.0 * * © 1994 by Ryan Cramer * */ define("NAME_FROM", '"Your Name Here"'); define("EMAIL_FROM", "you@domain.com"); define("REPLY_TO", "you@domain.com"); define("ERRORS_TO", "you@domain.com"); define("SUBJECT", "ProcessWire News & Updates - April/May 2013"); define("SECONDS", 3); // seconds delay between each email sent define("TEXT_ONLY", false); // set to true if not sending HTML email define("TEST_MODE", false); // set to true if just testing a send define("TEST_MODE_EMAIL", "you@domain.com"); // email to send to when testing define("SUBSCRIBERS_FILE", "subscribers.txt"); // file containing subscribers, 1 email per line define("TEMPLATE", "template"); // file containing email to send: template.html and template.txt define("X_MAILER", "GhettoMailer 1.0"); /**************************************************************************************/ ini_set("auto_detect_line_endings", true); function mailTextHtml($to, $subject, $message_text, $message_html, $headers) { // exactly like regular mail function except sends both text and html versions $semi_rand = md5(time()); $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; $headers = trim($headers); // in case there is a trailing newline $headers .= "\nX-Mailer: " . X_MAILER . "\n" . "MIME-Version: 1.0\n" . "Content-Type: multipart/alternative;\n boundary=\"$mime_boundary\""; $message = "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/plain; charset=\"utf-8\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . "$message_text\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/html; charset=\"utf-8\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . "$message_html\n\n" . "--{$mime_boundary}--\n"; $success = @mail($to, $subject, $message, $headers, "-f" . ERRORS_TO); return $success; } /**************************************************************************************/ $start = 0; if(!empty($_GET['start'])) $start = (int) $_GET['start']; $subscribers = file(SUBSCRIBERS_FILE); if(isset($subscribers[$start])) { $line = trim($subscribers[$start]); $total = count($subscribers)-1; $email = trim($line); $subject = SUBJECT; if(isset($_GET['pause'])) { $meta = ''; $content = "[$start/$total] Paused. <a href=\"email.php?start=$start\">Resume</a><br />"; } else { $meta = '<META HTTP-EQUIV=Refresh CONTENT="' . SECONDS . '; URL=./email.php?start=' . ($start+1) . '">'; $content = "[$start/$total] Emailing <u>$email</u><br />" . '<a href="email.php?pause=1&start=' . ($start+1) . '">Pause</a><br />'; if(TEST_MODE) $email = TEST_MODE_EMAIL; $headers = "From: " . NAME_FROM . " <" . EMAIL_FROM . ">\n" . "Reply-To: " . REPLY_TO . "\n" . "Errors-To: " . ERRORS_TO; $content .= "Subject: <b>$subject</b><br />"; $bodyText = file_get_contents(TEMPLATE . ".txt"); if(TEXT_ONLY) { mail($email, $subject, $bodyText, $headers, "-f" . ERRORS_TO); } else { $bodyHtml = file_get_contents(TEMPLATE . '.html'); mailTextHtml($email, $subject, $bodyText, $bodyHtml, $headers); } $handle = fopen("email.log", "a"); if($handle) { fwrite($handle, "[$start/$total]: $email\n"); fclose($handle); } } } else { $meta = ''; $content = "Subscriber emailing finished. $start emails sent."; } ?> <html> <head> <?=$meta; ?> </head> <body> <?=$content; ?> </body> email.php2 points
-
Hi Madmax555, Welcome to PW! About SQL injections in PW, see the answer by Ryan (main developer) in this thread - they are a non-issue with respect to PW API These will also be useful http://processwire.com/talk/topic/1380-duplicate-entries-registration-form/?p=12369 http://processwire.com/talk/topic/314-idea-create-calendar-events/?p=2183 http://processwire.com/talk/topic/1380-duplicate-entries-registration-form/ http://processwire.com/talk/topic/2038-distinct-selector-in-processwire/?p=19268 http://processwire.com/talk/topic/2385-custom-string-in-names-of-database-tables/1 point
-
1 point
-
Sure you cleared the cache from the overview page? Most likely the problem. Otherwise check your selector which generates the listing. Usually selectors only select published pages, but if you have something like include=all in it, it will also select unpublished pages. Also: Be sure not to be logged in as superuser.1 point
-
jQuery is a great example of how a frontend framework can be useful – it makes writing JS way easier (some people would not agree that this is a good thing), takes care of browser issues (unless you use the new jQuery 2.0 and still have to support oldIE) and even makes using JS safer. But it does not impose things on the user like a lot of CSS frameworks do. That is, until you start using jQuery plugins, because some of them require specific CSS to work. The thing with CSS framework is, most of them include a UI component, much like jQuery has jQuery UI (but doesn't bundle it). It would be perfectly okay to use e.g. Bootstrap's layout module, but most people just download the whole thing and use it. (I'm not even sure if you can download just “the good parts”.) So a pretty good indicator for a usable CSS framework would be that it's modularized in a way that you can choose which modules you want to use. If if even has a generator which gives you an individual build, great. But if it is split into modules but still ships the whole nine yards in any download package …1 point
-
1 point
-
Diogo, I think it depends how you use the framework. Personally I get great use out of the responsive grid and a few defaults like form elements. I certainly try and avoid using the very obvious Bootstrap TopBar or anything like that. I wouldn't say that any of the actual design is compromised by my use of Foundation. Also on their site, you can select which parts to include in the download so that you don't end up with the bloat. The biggest advantage for me is not having to worry (or worry as much ) about floats and cross-browser issues and it lets me spend more time on the actual design process1 point
-
Horst Simply a-ma-zing! I'm liking this more and more..1 point
-
Hi kongondo, I don't have a problem using XAMPP, I've already installed the package for windows, but I'm having trouble figuring out the next step. I've got ProcessWire zip downloaded, unzipped, and placed in my document. Obviously, I have to run XAMPP, but what do I do next? I'm from the Renoise Forums. My name over there is 2 daze j, my twitter name is jonathan_five, so I guess since I signed up here with my twitter account, I used my twitter name to match. Here is the thread @ Renoise where this software came up. http://forum.renoise.com/index.php?/topic/37801-are-more-people-choosting-joomla-over-drupal/ Its fancy meeting you here.1 point
-
Hi BrendonKoz, For an active project I'm using Pw templates and fields to model/store my data coming from another database. But I don't let users see the Pages tree. For some data, I'm not using the ProcessWire 'ProcessPageEdit' Process to edit the pages. I created my own Process module which displays the data from a page in a form. Then I save everything via API. This way you can quickly use standard form modules from Pw but you're also free to generate your own markup beside that. For example the repeaters could (maybe) be displayed in a table which doesn't eat up that much vertical space. With the 'InputfieldMarkup' module you can display whatever kind of stuff you like - would be a solution to display calculations / metrics for your second project mentioned.1 point
-
Awesome, thanks everybody. And thanks for the explanation, Ryan. I'm looking forward to improving my regexing1 point
-
$body = preg_replace('{<script[^>]*>.*?</script>}is', '', $body); $body = preg_replace('{<!--.*?-->}is', '', $body); The key here is to change the default "greedy" matching to be "lazy" matching using the .* followed by a question mark: .*? That ensures that it will match only to the closest closing tag rather than the [default] furthest one. That way it won't wipe out legitimate copy. Also the "s" at the very end lets it traverse as many lines as needed to complete the match. Without that, it would only match opening and closing tags on the same line.1 point
-
PWired, This article at A List Apart is a must read if you haven't seen it and are interested in responsive design. I wouldn't say responsive design is "hard". It's about being consistent and sensible . I am a firm believer of not re-inventing the wheel. For instance, no matter how good I was at coding (which am not, hehe), I wouldn't bother coding a PHP application to do what PW did because it's already doing all that I want and does it well. So I use the existing tool. This is not to discourage anyone from coding their own app. One should do so if there is a particular need not being met, IMHO. What am I saying? There's already dozens of HTML and CSS frameworks out there that do responsive design out of the box such as Bootstrap and Foundation. I love Foundation and it is what I use. I don't care about floats and DIVs misbehaving because Foundation takes care of that for me. Of course we might get into the argument about some frameworks using non-semantic classes, but I think at times that argument just gets in the way. Besides, leading frameworks now take such matters into account. These things have been tested with screen readers and perform really well. Just Google the subject. In a similar vein, in PW, most of the time I don't care about sql queries since PW takes care of that for me. I would suggest to find a good framework and use it. Of course you don't have to use all the bells and whistles it comes with. Download a custom build, the bare necessities and code away. So, no, it doesn't have to be hard. And you can still learn the basics of responsive design even as you use a framework. It's all about ems, %s and @media queries in CSS3 really These may be of interest... Which Is Right for Me? 22 Responsive CSS Frameworks and Boilerplates Explained | Design Shack Fluid Images — Unstoppable Robot Ninja css3-mediaqueries-js - css3-mediaqueries.js: make CSS3 Media Queries work in all browsers (JavaScript library) - Google Project Hosting Beginner’s Guide to Responsive Web Design - Treehouse Blog What The Heck Is Responsive Web Design? Responsive Web Design Patterns | This Is Responsive Responsive Web Design: What It Is and How To Use It | Smashing Coding How to Design a Mobile Responsive Website - UX Booth | UX Booth Media Queries for Standard Devices | CSS-Tricks 37 Responsive CSS Frameworks Every Developer Should See | Web Design Principles A List Apart: Articles: Responsive Images: How they Almost Worked and What We Need Edit: Difference between responsive, adaptive and fluid http://teamtreehouse.com/library/websites/build-a-responsive-website/introduction-to-responsive-web-design/fixed-fluid-adaptive-and-responsive Edit 2: Forgot to add - of course you'll still have your custom CSS file called after your framework's CSS to have the final say on styling particular elements. But you knew this already1 point
-
I don't think wappalyzer claims to be 100% correct, but if we take a vanilla installation of PW i think the combination of things above is enough reason to assume something is PW. The fact that you could quite easily make some customisations so that it can't be detected doesn't invalidate the wappalyzer tool (not that i particulary like it though). I'm thinking of adding <meta name="generator" content="Joomla! - Open Source Content Management - Version 3.0.0" /> to my templates just to throw them off.1 point
-
$page->of() is a short version of $page->setOutputFormatting(). This is what it says on the docs and cheatsheet:1 point
-
LinkMonitor won't be included in 2.3. It'll remain a separate module. I've not yet released it because I think there's a better way do accomplish what it is doing... just haven't figured it all out yet.1 point
-
The problem is source control - if it's data in a database, there is no file you can check in, compare version history or review changes made by other team members. Automated deployment becomes harder. You could dump SQL statements and check those in, but auto-increment keys make it extremely difficult to integrate, say, two different newly added fields or templates from different developers, since they will have the same primary keys. Just one example of many. Because metadata in nature is closer to code than it is to data, the metadata usually needs to be kept strictly in sync with the code - you usually have code that depends on the metadata, because the metadata "implements" (or at least strictly defines) the model. As opposed to data, which is usually less vulnerable to asynchronous deployment. I don't know if source-control and automated deployment are very important to most people - perhaps not a big concern for most smaller websites?1 point