Jump to content

ryan

Administrators
  • Posts

    17,140
  • Joined

  • Days Won

    1,657

Everything posted by ryan

  1. I recently installed a client site at GoDaddy (I tried to talk them out of it, but had to work with what they had). It was one of those $5/month sites, not a VPS. I had to change the RewriteBase in the .htaccess file to "/", but otherwise found that it worked just fine. Granted it's not speedy, but everything runs acceptably for a low traffic site. With ProCache installed it's actually quite fast. Based on the things you've said, I would guess that there's a bottleneck somewhere, and that the GoDaddy server is just making that bottleneck more obvious. Speed should not be significantly affected by quantity of pages in the site, so it points to something, somewhere in the site that is loading a large amount of pages (most likely a hook or module). I would enable debug mode, and then view the Debug info in the bottom of the admin screen on one of the slow loading pages (though not Lister, since it ajax-loads its pages separately). Click on the "Pages" section to see what's being loaded. I'm guessing you might have something in there loading all 2000 pages. This might help to point to the source of the bottleneck.
  2. It's like an enhanced repeater, but it doesn't actually use multiple templates. It uses just one, and pulls a few tricks behind the scenes to make it all work, while remaining perhaps more efficient than if it were using multiple templates. One other update I've been working on this morning for regular Repeaters, and now have functional (though have not pushed to GitHub) is making all repeater items ajax-driven, so they don't load until you click on them. This enables Repeaters to scale just as well as PageTable. It's a configurable option, but one that I think will be good to enable for folks that have lots and lots of repeater items... it should make a major different in editor performance.
  3. Thanks guys glad you like what you see! Actually I haven't done anything in that respect, other than add the option to have them be collapsed by default (something that's been requested by a few people). But I agree just having that option makes quite a difference. It is using pages in exactly the same manner as regular Repeaters. Repeater Matrix actually extends Repeater, in the PHP class sense. So the core Repeater class handles all the page management for Repeater Matrix. This also enables you to convert a Repeater to a Repeater Matrix field (or back again) just by changing the field type.
  4. This week is all about repeaters, something that we didn't cover on the roadmap last week–we always like to save a few surprises to keep things interesting. We've also got a preview of the new Repeater Matrix field coming soon to the ProFields package… Read the post here: https://processwire.com/blog/posts/processwire-3.0.4-repeaters-revisited-preview-of-profields-matrix/
  5. Happy New Year! Here's the ProcessWire 2016 roadmap: https://processwire.com/blog/posts/happy-new-year-heres-a-roadmap-for-processwire-in-2016/
  6. Okay if it works with 2.7.2 then it can be made to work with PW3. I installed it to take a closer look at what the issue was, and it came down to that PW3 doesn't support compiled admin themes at all. I'd forgotten that. I've updated PW3 to support compiled admin themes that live in /site/modules/, and that's now committed to the devns branch. Testing with AdminThemeModesta, it seems to work just fine. Though there's lots missing from AdminThemeModesta in terms of current feature support, so I'm not sure I'd recommend using it, but it should work now if you want it.
  7. @mrkhan, Modesta only shows compatibility with PW versions up to 2.4, so I'm not sure there will be an easy solution to use it with PW3 or 2.7 for that matter. There have been significant changes to admin themes between the last few 2.x versions and to my knowledge only the themes included with the core are working for 2.7 and 3.0. Though if you do manage to get it working, you may want to submit a PR to the author of the Modesta theme. I think you are on the right track with adding "namespace ProcessWire;" to the top of all the PHP files. This is something that will be necessary for an admin theme to support PW3 (unlike other modules). I think the reason you are getting the "trying to get property of non object" error is because Modesta is an admin theme module, rather than an older style admin theme. That means it would need to live in /site/modules/AdminThemeModesta/ and not in /site/templates-admin/. I can see from the error message that you've got it in /site/templates-admin/ rather than in /site/modules/. An alternative is that you may want to consider creating a custom color theme for the Reno admin, as we know the Reno admin theme supports everything in the current 2.7/3.0, but we don't know if Modesta does, even if you can get it working.
  8. Horst, I've not been able to duplicate this one here. The code I'm using to test: <pre><?php include("./index.php"); $test = $pages->get("/about/"); echo "$test->title - $test->sort - $test->modifiedStr\n"; $test->setAndSave('sort', $test->sort + 1, array('quiet' => true)); echo "$test->title - $test->sort - $test->modifiedStr\n"; Anything I'm missing with regard to reproducing it?
  9. Hey guys, this upgrade now appears on PW 3.0 (devns) branch. If you are using the ~= operator in a search, like "title~=disability act" it now asks MySQL for the ft_min_word_len (per @LostKobrakai's suggestion above). If any word length falls under that threshold, it delegates that word to a separate REGEXP command in MySQL that matches whole words. This is actually an improvement over the code I mentioned earlier because the previous code that converts it to use a "%=" for short words could match things like "disability fact" or "react to this disability" etc. Whereas the new core addition will only match whole words in the same way that the MySQL index would, meaning the field would only match if it contained the exact words "disability" AND "act" somewhere in the field, and not some word that happens to contain the partial word "act". To take it further, it also now uses this technique to match stopwords that MySQL doesn't full-text index. Previously it would just exclude them from the search since the presence of a stop word would prevent a search from matching. Now you can perform searches that include those stop words and match them.
  10. SiNNuT by "make it the default" I mean "make it the default when supported". When full-text isn't available for InnoDB, we couldn't use InnoDB for things like FieldtypeText/FieldtypeTextarea. I don't plan to drop MyISAM support, just default to InnoDB in the installer when we're identified that it can be fully supported in the environment. This could be a problem with migration, like when your dev server has the needed versions and your production server doesn't, so the installer will definitely need to call more attention to these considerations when providing the db engine selection at install time. Btw, we already do use InnoDB for some tables where we want to avoid table locking (like DB sessions).
  11. ryan

    ProcessWire on the web

    This is actually one area that I think may be too broad in scope for a tuts plus tutorial. That's because PW doesn't generate markup nor does it have an official front-end forms API, so it would be much more of an HTML and PHP tutorial than a ProcessWire one. Keep in mind the guides there are to demonstrate the simplest possible cases. We use concatenation because it's really simple and easy (and what I prefer), but that doesn't mean it's a requirement of delayed output. You could just as easily use arrays, output buffering, wireTemplateFile(), wireIncludeFile(), etc. The point is to demonstrate delaying your output until the appendTemplateFile inclusion. That's what delayed output is. ProcessWire's API is a PHP API, so I find it a lot simpler to stay in that API rather than constantly jumping in and out of HTML. After all, it requires <?php ?> tags to jump in and out of PHP from HTML, but does not require anything but quotes or heredocs to use HTML within PHP. PHP alternative syntax is handy for large blocks of conditional HTML. But for most markup generation situations I don't recommend it unless you personally find it more readable. For many of us, the additional verbosity and constant jumping in/out of PHP & HTML make it difficult to read and follow, but this is purely a preference thing as I don't think it matters to the end result at all. When it comes to writing tutorials and/or documentation, I try to communicate the concepts in the simplest/shortest way possible so that focus remains on the concept and API calls that we are trying to teach. That doesn't mean you have to do the same, or that doing it differently means you aren't adhering to the concept. Whether you are using alternative syntax or not matters little to the concept. Though since you are in "direct output" when outside of a php tag, it does make your job a little harder for delayed output. But you can amend that by isolating your markup and rendering it with wireTemplateFile(). Fantastic! @benbyf and @isellsoap just let me know if there's anything I can do to assist. Thank you for writing tutorials for PW!
  12. er314 sorry I think I misunderstood, as I thought you were suggesting we change the behavior of the existing $pages->get() method, or make it have front-end vs. back-end state (which isn't really possible since PW's API has no front-end/back-end knowledge, and the context of the API is neither). But I'm glad you started this topic because, like I said, I think you've identified a reasonable addition to the API here that should help to further clarify the purpose of the methods for any that may have confusion. And if you and Teppo had confusion about it, then certainly others will too. We've had a $pages->findOne() method in our API since the beginning, but it's just been there as an alias to $pages->get() and just for backwards compatibility. I have dropped the purpose of that method in PW3, since we no longer need that backwards compatibility, and I very much doubt anyone uses it other than the core in a few spots (which I've updated to use the get method instead). I have changed $pages->findOne() to be an alternative to $pages->get() in PW3, that by default filters in the same way as $pages->find(). You'll see this in today's commits. I think this adds more clarity because one can now assume that any $pages method that starts with "find" is also "filtered" by default.
  13. I have to admit I would also like to free the emojis. PW should support utf8mb4 now at install time (click the gear icon on the DB config screen). There are some hard-coded utf8 references in the install.sql files (core and site profile) but the installer updates those before executing the queries (at least it should). And any create/alter table queries that occur after that (like when adding a field, etc.) use the $config->dbCharset that is setup at install time. It sounds like we need to update some column lengths though. Going from 255 down to 250 seems fine to me (for new installs). Though maybe a little more concerned about going down to 191 for InnoDB, especially since we'll probably make InnoDB our new default before PW3 becomes the new master branch. I'll look closer to see if there are situations where the indicated columns need more than 191. In PW3, we wouldn't change the character set or DB engine of existing installations, only new installations. @Pierre-Luc I completely missed your patch before. Sorry about that, sometimes I've got information overload here and it's easy for me to miss things (I think this is likely the case for all of us). I will definitely use and apply this. Thank you for creating it. We won't need the changes to the install.sql files though, since the hard coded db charsets in the install.sql files are updated dynamically by the installer. Though I will need to double check that is working, as it's been awhile since I've tested it. @BitPoet can you expand on why you think it might be possibly dangerous? I know it would certainly be dangerous if applied to existing installations (it would delete data). But I don't think we should ever have PW modify the charset or engine of existing installations. But for new installations, do you see any potential dangers?
  14. er314, I think your intentions are in the right place and I appreciate your determination. You are still asking for an established method with a specific purpose to have a different purpose and an access controlled front-end context, when that is not the purpose or full context of the method. So I hope you can understand why it's not realistic to just change the definition and implementation of an established method. But I get where you are coming from and think you've identified a potential helpful addition in the API, so I go ahead and add a "one" method or change the "findOne" method (in PW3) to behave as a "find just one" method with regard to access control, hidden/unpublished visibility settings, etc. While I don't personally think I will ever use this method, I think that you and Teppo have identified a couple of situations where some might find it handy. Even if one doesn't need it, perhaps just the presence of it in the API will further clarify the intentions of the methods as a whole, for folks that may have thought that the existing find() and get() were the same. I still worry a little bit about people forming an impression that PW's API is doing access control for them, when our entire API is based around providing methods for the developer to control access the way they see fit. The viewable() method is the basis of that. But we've already dipped into that territory with the find() method, and by adding the proposed method, we're not removing any control, just adding more options. So I think it's an okay. What I was stating is that I'm not aware of an instance where anyone has introduced security problems into their site as a result of using the get() method. Though you stated above that you did just that, so now I'm aware of an instance. You are correct that if a developer uses a $pages->get() method to retrieve a page that came from user input, and neglects to validate that the page is one you allow, then that could be a problem. But the same problem could surface anytime a developer neglects to properly sanitize or validate something–anything–that originated from user input. And this is not something you can skip regardless of what method you are using to retrieve a page or group of pages. Simply validating that a page is viewable does not mean it's valid for whatever operation you may be performing upon it. You would need to validate that it uses the expected template, comes from the expected parent, etc. So while we are adding a PW3 method to support your request, be careful not to get the impression that you no longer need to validate a page that originated from user input. Also keep in mind that a $pages->find() or proposed $pages->findOne() method that filters results is based on database-filtering, not runtime filtering. Part of PW's access control model supports runtime hooks to Page::viewable. If your situation includes any runtime access control options and pages you are loading as a result of user input, you shouldn't skip a $page->viewable() call regardless of what method you used to retrieve the page.
  15. Tom, there's a setting in MySQL called ft_min_word_len and the default is 4. That means that if you have any word in your query that is less than 4 characters, MySQL won't be able to match it unless that setting has been adjusted (and you've forced it to rebuild the indexes on your db/table). That's why you aren't able to match "Disability Act", because "Act" likely falls under your ft_min_word_len. You should be able to get the result you are looking for by using %= instead. But since you want to match "disability" and "act" anywhere in your search, you'd need to do this: template=document, title%=disability, title%=act The following code should use %= for words less than 4 characters and ~= for the rest. $search = $input->get->text("search"); if($search) { $selector = ''; $parts = explode(' ', $search); foreach($parts as $key => $part) { if(strlen($part) > 3) continue; // use MySQL LIKE for words under 4 characters in length $selector .= ", title%=" . $sanitizer->selectorValue($part); unset($parts[$key]); } if(count($parts)) { // use MySQL fulltext index for words 4 characters and higher $selector .= ", title~=" . $sanitizer->selectorValue(implode(' ', $parts)); } $results = $pages->find("template=document" . $selector); } else { $error = "Please enter a search term in the search box above."; $results = null; } Come to think of it, it might be nice if PW just did this for you automatically when it detected the condition... but we don't know what the ft_min_word_len setting is.
  16. What is front-end and what is back-end? That term is just for our point of view. The code powering the rest of PW doesn't know about this, nor does it know if you are using it for an access controlled website, or some command line API tool, or something else. While your front-end page is rendered, there might be several other core and/or 3rd party modules also doing other things (because they auto loaded, or they were requested by the page), and those modules in turn might be doing several of their own $pages API calls that have absolutely nothing to do with your output, user or access control. There is a much bigger picture than just what you are doing in your template file. The built-in filtering that you have on top of $pages->find() is actually a pretty unique case in the overall API, and the phpdoc for that method outlines it as a unique case. After all, find() is primarily used for lists and pagination. You have access to everything with your API code, but your code is not the user, and the user is not your code, so be careful not to blur those lines. The API is there to assist you in getting any content you need as quickly and easily as possible, but you are the gatekeeper. It's important to keep this in mind anywhere in the API. In the more than 5 years of this open source project, I'm not aware of any instance where someone has misused a get() method and caused a security problem. So we're talking about a hypothetical scenario of someone making a code error, that to my knowledge has never occurred before, though who knows. We could construct all kinds of scenarios where a developer could misuse the power provided and get themselves in trouble. PW is a tool that when used correctly, provides very strong security and its been my primary focus in this project. But I also don't believe in magic_quotes, safe_mode or trying to save developers from themselves by introducing obstacles. These things might seem to provide more security initially, but actually create a perception that one is no longer responsible for their own security and thus become security problems themselves. I have no qualms about an access controlled "one" function per an earlier post, which could be a useful shortcut for some developers and scenarios. But I think it's important that such a method is completely distinct and also outlined as a unique case, because PW's API context is one where the site/app developer using it carries that power and responsibility. We like to access control the user, not the developer. It's good to see this Security board finally getting some discussion.
  17. What you are describing is a coding error. Any time someone uses function/method calls improperly, especially when user input is involved, they are creating a vulnerability. This has nothing to do with PW. This is the world we live in. I fully support trying to anticipate mistakes a developer might make and saving them from themselves. But a $pages->get() method with a stated purpose of retrieving a specific page unconditionally is not the place for it. I am however open to adding a different method with a different purpose. If we did have it, we could expect a whole lot of things to break when it is enabled. The behavior of get() is fundamental to the application logic of PW and sites/apps built upon it. Because a get_is_like_find option would make the get() method perform as something entirely different from what it is, we could expect much of the API to be broken. The intended consumer of a get() result (and most API calls for that matter) is the developer. The get() method has nothing to do with users or access, and everything to do with retrieving the specific page you asked for. You are operating on the assumption that get() is there for a different purpose, like specifically for output. Yes there may be cases where one may want to retrieve a single page and also have it bundle in some access checks, but that would be a different purpose and a different method.
  18. PW provides access control for the request. Once that request is successful, it's between the developer and the API what they want to do. The API is not jailed and not intended to be. If one is dealing with user input, they must sanitize and validate that input. PW works like PHP does in this respect. That means if you are going to start grabbing pages that are influenced by variables from user input (like in Teppo's scenario), then you have to sanitize that user input and validate the result, regardless of what method you've retrieved the page(s). The purpose of get() is to get a specific page that you asked for. The purpose of find() is to find pages that you don't necessarily know what they will be. With find(), since you don't know exactly what pages you'll be retrieving, filtering that result makes a lot of sense as a default behavior. But with get() you are asking for something specific that you know about ahead of time, not some unknown result as with find(). So it makes little sense to apply the same logic to get(), and it would run counter to the purpose of it. I'm not interested in changing the purpose of get(), which works exactly how it's supposed to and intended. I also don't want for there to be an implication that the API is doing everything for you in terms of access control, when that is not the intention or design of it. Where would it end? Blocking $pages->save() API calls and the like? That is not PW. The API does not run in a jailed environment by design, instead it provides dedicated methods for access control. The API is there to give you great power, and yes we expect the developer to use it responsibly. We expect that when a developer makes an API call, they know what the method is for. The get() and find() are entirely different methods with different purposes that are clearly documented. What I'm gathering from er314 and Teppo is that the concern is people using the get() method without a proper understanding of what it's for, or applying what they know about find() to the get() method, even though they are entirely different animals. I don't believe we should intentionally handicap methods to gear them towards people using them improperly. But if it's a concern or enough demand for it, I'm happy to add another method (like the "one" method I used as an example above) for that alternate purpose. Perhaps it'd be useful in a couple of the scenarios Teppo described above if the developer wants to get a page and check for access in one method call, saving a line of code.
  19. Nice work Diogo! True story, I actually had a dream last night that I went into a big fancy department store to do Christmas shopping and there was a metal plaque on the door that said "Design by Ed". When I went in, everything was super minimal and modern like an Apple store, but much more so. It was like all the products for sale, and all the customers, were treated with the highest amount of respect by the designer. But here's the kicker, it was snowing in the store! (this was last night, well before you posted this) No snow for us here either. Our Christmas day forecast is rainy and 75 degrees (24c). That's too hot to even use the fireplace. Bummer.
  20. When using PW's API, you should always consider your code to be operating as a kind of superuser, just like in PHP. In find() operations where you are retrieving multiple pages that you don't know exactly what they will all be, it's a sensible default to exclude "hidden", "unpublished" and no access pages, unless you request otherwise. This is there as a matter of convenience and pagination, not security. Of course you can override that (when you want to) with the "include=hidden" or "include=unpublished" or "include=all" options. Whereas with get() you are being very specific about what you want–a single specific page. Otherwise why would you get() it? Neither find() or get() are intended as a primary means of access control–we have other methods for that (see below). They are methods setup to operate in the most common use cases and keep your API calls as short and simple as possible. Just because find() filters out hidden, unpublished and no-access pages by default does not mean you should count on it for access control. That's because the pages excluded from a find() don't include runtime access control, just that which is stored in the DB. Further, the behavior of whether or not a no-access page shows up in a find() result (that isn't overridden with an include= directive) is configurable with template access settings. Granted, in most cases find()'s defaults are giving you exactly what you want in terms of excluding pages the user can't view (for your convenience), but that's not the entirely of PW's access control, which supports runtime hooks. PW's job is to provide access control for the request, but not for your own code, that's the developers job. PW intends to give you, the developer, access to everything (like you would with jQuery and the DOM), and you decide whether or not it should be available for output. PW provides you with some handy access control methods to help with this: $page->viewable(); // is the page viewable? true or false $page->viewable('field_name'); // is the field on page viewable? true or false $page->editable(); // is the page editable? true or false $page->editable('field_name'); // is the field on page editable? true or false If you want to have you own get() and find() that operate under different defaults, this is easy to do with hooks in your /site/ready.php file. For instance, this would add a $pages->one("selector"); method that automatically does a viewable() check for you and returns a NullPage() if the page is not viewable: $pages->addHook('one', function($event) { $page = $event->object->get($event->arguments(0)); if($page->id && !$page->viewable()) $page = new NullPage(); $event->return = $page; }); Would there be value in adding a method like the above to our $pages API by default? Maybe. It wouldn't benefit my own API use, because the only time I use $pages->get() is because I want to get something without conditions. But if it would be super handy for others I'm happy to add it. Here's another example, lets say you want a method in $pages, like $pages->all("selector"); that always returns all pages with "include=all" implied: $pages->addHook('all', function($event) { $event->return = $event->object->find($event->arguments[0], array('include' => 'all')); });
  21. Makes sense to me, I'll move that <?php endif; ?> down one line, so that the name/version only appears when logged in.
  22. Testing here with PW 2.7.2 in a new URL field I setup called "href", I used the URLs you mentioned. For my field settings, I have "Allow single/double quotes" set to true, and for "Text formatters" I have "HTML Entity Encoder" selected. I tried with and without the "allow IDN" option, but it doesn't matter here since we're not testing with IDNs. Here are the results I got: https://en.wikipedia.org/wiki/Peter_O'Toole Input to URL field in admin: https://en.wikipedia.org/wiki/Peter_O'Toole API code to output: echo "<a href='$page->href'>test</a>"; Output in rendered page: <a href='https://en.wikipedia.org/wiki/Peter_O'Toole'>test</a> Result: Clicking the link works, taking me to the page on Wikipedia https://upload.wikimedia.org/wikipedia/commons/5/53/Peter_O'Toole_-_1968.jpg Input to URL field in admin: Input to URL field in admin: https://en.wikipedia.org/wiki/Peter_O'Toole API code to output: echo "<img src='$page->href' />"; Output in rendered page: <img src='https://upload.wikimedia.org/wikipedia/commons/5/53/Peter_O'Toole_-_1968.jpg' /> Result: Picture of Peter O'Toole Basically, it's working exactly how it should. My best guess is that it wasn't working for you because you've got some other code in there somewhere HTML entity encoding the URLs, to make up for the bug prior to 2.7.2 where text formatters weren't being properly applied to URL fields. Another possibility, check if your $page possibly has output formatting turned off? It would need to be ON for this all to work. That's interesting, so it looks like the URL is getting URL encoded, converting the apostrophe to a %27. I did try entering that too, but PW converted it back to an apostrophe and then entity encoded it, resulting in the same working output as in my second test above. If this is literally how your URLs are stored in the database, then my best guess is that when you are outputting the value, either the $page's output formatting is off for some reason, or the HTML entity encoder wasn't selected in your "text formatters" details tab, which would prevent a URL with an apostrophe from working, whether it was URL encoded or not. I would suggest upgrading again to 2.7.2 and double check all your settings, especially the one about allowing single/double quotes and the Text Formatters. If the URLs are still not working, then check to make sure in your template file that the page's output formatting is enabled, like this: if($page->of()) { echo "<p>Output formatting IS enabled</p>"; } else { echo "<p>Output formatting IS NOT enabled</p>"; } If it's not enabled, you'll want to track down where you are turning it off, typically with a $page->of(false); or $page->setOutputFormatting(false); Finally, check that you don't have something else entity encoding the URLs in your site. If you've got a line like this, you'll want to remove it: $page->bfd_image_from_url = htmlentities($page->bfd_image_from_url); // avoid this
  23. BFD what's an example of the exact URL as you have it input in the admin page editor, and what's an example of the exact output you get in your source on the front end? For your field settings, what textformatter plugins are being applied (details tab), if different from before? You mentioned the URLs were working before, when actually they really shouldn't have, so I'm wondering if they might be getting double encoded somewhere along the line. If some of your URLs are input encoded and some not it might be that you need to output the value a little differently on your front end to account for that. But I need to know what the exact inputs and outputs are first.
  24. I'm waiting for the coffee to kick in still, so this probably is missing something but I'll throw it out there anyway... text_field*=cat|dog, page_field=1234|4321 Btw, for some of the solutions above you can also leave out the "foo=" part if you want too. You only need to start naming the OR expressions if there are multiple OR expressions that should be evaluated as part of separate groups. But if you need a "bar=" too, then you'd need to name them.
  25. Tom, sorry that field was behind a showIf dependency for the inline edit fields checkboxes, like Adrian mentioned. It's actually only supposed to apply to those checked fields, which is why it didn't appear. I was replying from mobile before and was forgetting this. That particular setting really is only meant to apply to those checked fields, so your $page->edit() wasn't working as a result of a bug, which I have pushed a fix to 3.0.2 just now. You should now be able to use $page->edit() with any field regardless of page. There's no concern about performance hit here. The reason it's recommended off is only as a default setting. For instance, let's say you've got a "summary" field in your page and you are rendering search engine results that include that summary. You probably don't want the summary to be editable in all those search engine results, whereas you do want it to be editable when you are actually on the page. So the setting is just there to reduce confusion since chances are, most of the time you'll only want to have a field editable when you are on the page it is owned by. None of this is meant to apply to options B through D since you are already in control of it all from the API side. I don't think there's much we can do about it, if that image is not part of your field there. However, if it's a concern, you may be able to add something like this to your css file to adjust the cursor: #your-container img.your-image { cursor: pointer; }
×
×
  • Create New...