-
Posts
17,151 -
Joined
-
Days Won
1,668
Everything posted by ryan
-
I agree. I think this is something we'll definitely have to do. Would be great to have a 1-step backup that includes database and site files. Though it could be a slow process for very large sites.
-
Looks like great solutions. Here's one more: <?php function treeMenu(Page $page = null, Page $rootPage = null) { if(is_null($page)) $page = wire('page'); if(is_null($rootPage)) $rootPage = wire('pages')->get('/'); $out = "\n<ul>"; $parents = $page->parents; foreach($rootPage->children as $child) { $class = ''; $s = ''; if($child->numChildren && $parents->has($child)) { $class = 'on_parent'; $s = str_replace("\n", "\n\t\t", treeMenu($page, $child)); } else if($child === $page) { $class = "on_page"; if($page->numChildren) $s = str_replace("\n", "\n\t\t", treeMenu($page, $page)); } if($class) $class = " class='$class'"; $out .= "\n\t<li>\n\t\t<a$class href='{$child->url}'>{$child->title}</a>$s\n\t</li>"; } $out .= "\n</ul>"; return $out; } Usage: <?php // no params: print out tree menu from current page to root parent echo treeMenu(); // or specify what you want it to display echo treeMenu($page, $page->rootParent);
-
Sounds good. I will put together a code sample. I'm leaving to pick up my daughter from school now, so may not be back online for awhile. But I will post as soon as I can.
-
Are you looking for something that generates a nested list from current page down to homepage? That's what it looks like, but I just wanted to double check.
-
Great it looks like it works for me once I added those! Cool fieldtype. My computer doesn't recognize something about the language/localization, as all the buttons are a series of question marks. But I think that's just because my computer must not have that language installed. I'm wondering if it would still work if you output those two scripts from your formatValue function, since you are already outputting an inline script there? Though it may be that Google Maps requires it to be loaded in the <head> section, I'm not sure. Also, I recommend placing your GMap module in /site/modules/ rather than /wire/modules/. This is because /site/modules/ is for user-installed Fieldtypes, whereas /wire/modules/ is for Fieldtypes that are permanent. When you upgrade ProcessWire, you replace the entire /wire/ dir, so you don't want to put anything custom in there. Whereas everything in /site/ is custom to your site, so any modules you put into /site/modules/ won't get overwritten when you upgrade ProcessWire.
-
What is the context of where that error occurred? Are you trying to load ProcessWire from Drupal? If so, it sounds to me like Drupal probably has it's own "User" class that is conflicting with ProcessWire's. You may be better off using ProcessWire as a web service in this case. That RSS feed module I posted yesterday would be a great way to pull the data into Drupal.
-
I installed it and tested it – very cool! It looks like you already know how this all works. And it looks like your Fieldtype is nearly functional on the front end too. This helps me to see what you are doing, and I should be able to answer any questions you have more easily now. Actually I've been wanting to make a Google Maps fieldtype, so am happy you are making one already. Just let me know if there is anything I can do to help. Thanks, Ryan
-
Sounds like a good idea to me. It's possible it may be easy to implement, but I need to do a little more research.
-
For any page where you want to move it, just get the parent page, and set the target page to have that parent, and save: $page = $pages->get("/home/mypage/"); $page->parent = $pages->get("/"); $page->save(); or if you want to do it on one line. -- $pages->get("/home/mypage/")->set('parent', $pages->get("/"))->save(); You'd use the same method to change a bunch of pages: $parent = $pages->get("/"); foreach($pages->find("parent=/home/") as $page) { $page->parent = $parent; $page->save(); }
-
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>
- 63 replies
-
- 19
-
-
Welcome to the forums Queryeee. I'm glad to see you experimenting with Fieldtypes. Your formatValue() function looks correct. Though you are using it in a different way than I've seen before. So I wanted to pass along some info that I thought might help in the context you are using it. First off, I would suggest that you post your entire Fieldtypetest class, because I want to make sure the other prerequisites are accounted for. Fieldtypes define database schema for a type of field, they identify an Inputfield to handle input, they sleep and wake values for going to/from the database, and they handle sanitization and formatting of their type of values for pages. I want to make sure that your Fieldtype is covering these areas, because it may not work otherwise. When you create a new Fieldtype, you should capitalize the "test" part, like FieldtypeTest rather than Fieldtypetest. When you've successfully created a new Fieldtype module, you have to install it in Admin > Modules. Then you have to create a new field in Admin > Setup > Fields, and choose "test" as your fieldtype. Then you'll add that field to one or more templates, making it apply to any pages using those templates. I'm going to assume you already know all this, but I wanted to mention it just in case. Fieldtypes can optionally specify a formatValue() function to handle runtime formatting. Most fields don't use it, but some do. Examples of fields that use it are text fields where you've added markdown or entity encoding formatters to it. And date fields also use outputFormatting to show formatted dates when it's ON and unix timestamps when it's OFF. The formatValue function is triggered every time you call $page->testField (or any field) and $page->outputFormatting == true. By default, $page->outputFormatting is always TRUE in your web site, so you don't have to think about it unless you need an unformatted value. However, if you are using the API from admin modules or command line scripts, then $page->outputFormatting is FALSE by default. For fields where it matters, you want outputFormatting to be TRUE when you are outputting values for presentation to a web site, but you want it to be FALSE when you are manipulating those values and saving pages. So for those fields, if you try to modify their value on a page when outputFormatting is TRUE, and then try to save the page ($page->save), ProcessWire will throw a fatal error to prevent you from corrupting the data. Why? If it didn't, then you might end up saving values to your page that have runtime formatters applied to them... so the next time you view that page, you'd have double-formatted values, i.e. two <div> tags rather than one, in your case. Luckily, ProcessWire prevents you from doing that. You can set whether outputFormatting is on or off for any page by calling: $page->setOutputFormatting(true or false); If you aren't seeing your <div>...</div> in your $page->testValue, then I'm guessing that $page->outputFormatting is FALSE in the place where you are using it. If you want to confirm, you can do this: echo $page->outputFormatting ? "ON" : "OFF"; However, if you are doing this from one of your site templates, it is going to be ON unless you've specifically turned it off. So if that is the context you are in, then I'm also confused why you aren't seeing your value with the <div></div> between it... and why I think it may be a good idea to post the class file here (or email to me if you prefer). Next, lets look at: $this->config->scripts->add(...) ProcessWire admin uses that a lot so that markup generating modules (Inputfield and Process) can tell it what scripts to load in the admin template. If you look at /wire/templates-admin/default.php, you'll see something like this in the <head> section: <?php foreach($config->styles->unique() as $file) echo "\n\t<link type='text/css' href='$file' rel='stylesheet' />"; foreach($config->scripts->unique() as $file) echo "\n\t<script type='text/javascript' src='$file'></script>"; ?> ProcessWire can do this because it's for it's own use, in the admin panel. But it won't make any assumptions about your own templates. It doesn't know or care what you are doing with your own templates, so it's not going to output <script> tags. As a result, if you want to use $config->scripts or $config->styles, then your template will have to do something like the above. And it's perfectly fine to use $config->scripts and $config->styles, that's what they are there for. If you want that script included without your template having to account for it, then I would suggest doing it inline. So your formatValue function would include the <script src='...'></script> tag directly in the returned value, after the </div>. I know that inline scripts are not a best practice in regular markup, but that is in lieu of other factors. if you are trying to build a self-contained Fieldtype that needs to output markup, and you don't want to have to add markup anywhere else, then it would be acceptable to output the <script> tag as part of your value.
-
Given a PageArray of pages, this module will render an RSS feed from them. This is intended to be used directly from a template file. Installation Download the RSS feed module at the bottom of this message. To install, unzip and place the file in /site/modules/. Go into Admin > Modules and click "Check for new modules" at the bottom. Then click the "install" button for the "MarkupRSS" module. From there, you'll be able to configure several aspects of the module. Usage Create a template in ProcessWire and use the following example as a guide. See the actual .module file for more configuration options too. <?php // retrieve the RSS module $rss = $modules->get("MarkupRSS"); // configure the feed. see the actual module file for more optional config options. $rss->title = "Latest updates"; $rss->description = "The most recent pages updated on my site"; // find the pages you want to appear in the feed. // this can be any group of pages returned by $pages->find() or $page->children(), etc. $items = $pages->find("limit=10, sort=-modified"); // send the output of the RSS feed, and you are done $rss->render($items); This module is now included in the ProcessWire core.
-
Okay great, glad you resolved it. And also glad it wasn't a forum error.
-
I got an email notifying me of a new post with the title "Page field problem", but now that I get to the forum, I can't find it. Just wondering if whoever posted it was able to solve this problem (and deleted the post?) or if it didn't post due to some error in the forum? I haven't had that happen before, so just wanted to double check.
-
Great, thanks. I will test some more here and then commit it. Good idea about adding the allowRelative option!
-
Actually default sorting is already there: 1. Edit the parent page of the children you want sorted in the admin. 2. Click the "children" tab, and then the "sort settings" link. 3. With the sort settings open, choose the field that you want to sort by. Save. Now the results will appear in that order in the admin, as well as when you do a children() call from the API. Of course you can always override it from the API by specifying your own "sort=" selector in the children() call. But the method described above is how you setup a default sort for children of any given parent page. This is how they will appear in the Page List. In my own sites, I use this particular feature all the time. For instance, on news/press items, I always want them reverse chronological according to a date field. In company directories, I sort them by person's name A-Z. And for other pages where I want to control the order with drag-and-drop, I don't set a default order. Let me know if I've misunderstood your question? But lets say that you are sorting by a "last_name" field, and it's different from your "title" field. You want "last_name" to appear in the Page List because it will be easier for you to find your pages that way? 1. Go to Admin > Modules > Process > Page List 2. Set the "name of page field to display" to "last_name title". Save. Now it will display "last_name" in addition to the title for any pages that have that field. For all other pages, it'll display the title, as it does now. You can take this further by entering more field names in that space. This is handy for this theoretical situation, as well as displaying pages with dates (when they have them) along with the title, and other things. Let me know if this helps?
-
I've got to do more testing, but here's the solution I came up with that I think accomplishes what you want. I added an extra path() function to the Sanitizer class, to handle the relative URLs. Also, the class file is attached (in a ZIP) if you want to try it. <?php /** * Return the given path if valid, or blank if not. * * Path is validated per ProcessWire "name" convention of ascii only [-_./a-z0-9] * As a result, this function is primarily useful for validating ProcessWire paths, * and won't always work with paths outside ProcessWire. * * @param string $value Path * */ public function path($value) { if(!preg_match('{^[-_./a-z0-9]+$}iD', $value)) return ''; if(strpos($value, '/./') !== false || strpos($value, '//') !== false) $value = ''; return $value; } /** * Returns a valid URL, or blank if it can't be made valid * * Performs some basic sanitization like adding a protocol to the front if it's missing, but leaves alone local/relative URLs. * * URL is not required to confirm to ProcessWire conventions unless a relative path is given. * * Please note that URLs should always be entity encoded in your output. <script> is technically allowed in a valid URL, so * your output should always entity encoded any URLs that came from user input. * * @param string $value URL * @param bool $allowRelative Whether to allow relative URLs * @return string * @todo add TLD validation * */ public function url($value, $allowRelative = true) { if(!strlen($value)) return ''; // this filter_var sanitizer just removes invalid characters that don't appear in domains or paths $value = filter_var($value, FILTER_SANITIZE_URL); if(!strpos($value, ".") && $allowRelative) { // if there's no dot (or it's in position 0) and relative paths are allowed, // we can safely assume this is a relative path. // relative paths must follow ProcessWire convention of ascii-only, // so they are passed through the $sanitizer->path() function. return $this->path($value); } if(!strpos($value, '://')) { // URL is missing protocol, or is local/relative if($allowRelative) { // determine if this is a domain name // regex legend: (www.)? company. com ( .uk or / or : or # or end) if(preg_match('{^([^\s_.]+\.)?[^-_\s.][^\s_.]+\.([a-z]{2,6})([./:#]|$)}i', $value, $matches)) { // most likely a domain name // $tld = $matches[3]; // TODO add TLD validation to confirm it's a domain name $value = filter_var("http://$value", FILTER_VALIDATE_URL); } else { // most likely a relative path $value = $this->path($value); } } else { // relative urls aren't allowed, so add the protocol and validate $value = filter_var("http://$value", FILTER_VALIDATE_URL); } } return $value ? $value : ''; } Let me know if you think anything is missing here? I tried to duplicate what you added, and also account for the relative paths vs. domain issue. Thanks, Ryan Sanitizer-php.zip
-
The only issue I see is that dots can be in page names and filenames. So that leaves the question of whether "company.com" or "sitemap.xml" is a domain name or a relative path/file... This is a problem in the existing url() function too, I'm just not sure how to solve it. I think I'll err on the side of assuming a domain name if the path doesn't start with a ".", like "./sitemap.xml" or "../../sitemap.xml". I like your addition of the allowRelative option. GitHub is great, or forum and/or email is fine too. Whatever you prefer. Thanks, Ryan
-
Jim, Thanks for posting that screencast. I'm aware of this particular issue, just haven't figured out how to solve it. I usually just move the item below the list, close the list, then move it above. I think this only happens in that specific location (right under the homepage), so it's probably an easy fix, I just need to track it down. This is one of those issues I run into every now and then, but forget about it. Now that I've got a video, I can't forget about it. So hope to have this one fixed soon. Do you have any more details on how to duplicate the other issue that initiated this thread? I still cannot duplicate it, and might need a more literal explanation of exactly what it takes to duplicate it. If for some reason I still can't duplicate it by April, you'll have to show me when we're up there for Hanna's birthday, and hopefully we can fix it then. Thanks, Ryan
-
A couple more things I wanted to add now that I'm at the computer (rather than the cell phone). There are more details about pagination here: http://processwire.com/api/modules/markup-pager-nav/ There's more information specific to your question under the section called "Are there any side effects?" The other thing I wanted to mention was your use of sorting by "id". The id is not something that you can necessarily count on 100% for sorting, because it's generated by MySQL. For the most part it's probably going to give you the result you want (at least in the short term), but it's also possible that it will be out of order from your other IDs (it all depends on MySQL and whether it ever reuses old IDs). This may never be an issue. But if you want to play it safe, you may be better off sorting by "-created" (date created) rather than "-id". I believe it will give you the same result you are expecting, but without the risk of relying upon a MySQL id.
-
For the results where you don't want pagination, add "start=0" to the selector. So in total it would be: "limit=10, start=0, sort=-id" (though it doesn't matter what order you place these in)
-
How do I save contact form submissions as pages?
ryan replied to Jim Yost's topic in API & Templates
It should accept paths -- that's the way I usually use it. You may be fine to use the PW InputfieldImage for your file uploads. But what I just wanted to communicate is that it was designed for a different context (an administrative context). So if you do use it, double check and understand what it's doing ... making sure that it's providing the security that you want relative to your server environment. If you see anything that you think should be changed or added to it, of course I'll be glad to upgrade it. If you decide you want to use it, let me know and I will also take a magnifying glass to it and walk through it in the context of non-administrative/anonymous use. Thanks, Ryan -
How do I save contact form submissions as pages?
ryan replied to Jim Yost's topic in API & Templates
Are you saving images using ProcessWire's image field, or your own? I would recommend using your own, just because ProcessWire's file/image fieldtypes were designed specific to the PW2 admin. Granted it might work well, but it was designed for administrative use rather than anonymous use, and I'd like to certify it for that use before I'd feel 100% comfortable with using it in that context. I'm always paranoid with anything that involves uploading files to a server. I've always felt that a best practice is not to allow anonymous users to upload files to the server. But in lieu of that practice, here's a few best practices I follow, though most are probably obvious. 1. Make sure that anything they upload matches known file types/extensions. Ensure that your extension check can't be mislead, as people will try to upload filenames with two extensions, nulls, dots, slashes, misleading UTF8 characters and other strategies to disguise the real extension. 2. Make sure that the uploaded files go into a non-web accessible location until confirmed that they are valid. If possible, have a real person involved to determine if they are valid. Depending on the context, this may not be possible. But if it is, then do it. 3. When files are ultimately placed in their web accessible location, make sure that no files can be executed in that location. This is just an extra safety measure. For instance, see ProcessWire's htaccess file to see how it disallows some file types from being requested in certain locations. With file uploads, I might only allow files of type GIF, JPG, JPEG, or PNG to be requested from the target dir (assuming the file upload were for images). 4. Convert your filenames to your own format. If there is some id number associated with the upload, use that number for the basename. If you want to retain the user's original filename, then convert it to ascii before placing in the target location. ProcessWire's $sanitizer->pageName() function is a good way to do that. 5. Check your PHP max_upload_size and max_post_size to be sure they are set consistently with the max file size you want to allow. Or, check the file size after upload, and delete anything bigger than what you allow. The max upload size that you can set in the POST vars is pointless from a security standpoint. 6. Be prepared for a million copies of c99.php disguised as other types of files/images.