-
Posts
17,090 -
Joined
-
Days Won
1,638
Everything posted by ryan
-
These things aren't in the repeater at present. But the repeater fieldtype is still in it's first version, so will be expanding upon it and these seem like good ideas.
-
I'm not sure about the implementation side in this module, or whether this is a good idea for the module or not. But on the ProcessWire PageList side, the client would have to lack view access to the pages in order for them not to see them in the tree. That could also be handled on the fly by the module with a hook to Page::viewable. There may be other ways too I'm not yet thinking of.
-
SmartyPants is separate from Markdown, though the two often go together. I think they are both originally from the same author actually. SmartyPants just adds auto replacement of regular "quotes" to curly “quotes”, replacement of straight apostrophes to curly apostrophes, replacement of 3 dashes to em dashes, replacement of two dashes to en dashes, and replacement of 3 periods to ellipsis. As far as I know, the language support is limited to those that would use those characters. Since what SmartyPants does is all pretty simple, it wouldn't be too hard to make a textformatter plugin for another language that does something similar. I think the quotes and apostrophes are the only ones that require some context logic to make sure they are going where they should and not where they shouldn't.
-
Thanks for posting this, these seem like some useful additions and some good insights on sitemap.xml too.
-
This thread started as a result of our 1500th post, and we are now well over our 15,000th, in a relatively short period of time. Now thinking of the huge celebration we should have when we reach our 150,000th post. Thanks to everyone here for making this such a great community! --- Edit: I removed the 500th member thing, as Pete correctly pointed out to me that the system still has some banned users in it, so we don't have a way of telling exactly who the 500th real member is. Sorry Ralph99.
-
I've put together a Process module skeleton that may be good as a starting point for any Process module. It is well commented and fully functional as a demonstration. It also includes instructions on what to do with it when using it as a starting point for another module: http://modules.proce.../process-hello/ I'm planning to make more skeleton modules to cover all the bases.
-
That comment is still the old version before the page was saved. You might need to re-retrieve it from the page in order to get the version with the populated ID. But this may be something you could just drop into your existing code without having to change much else: $email = $this->db->escape_string($comment->email); $status = Comment::statusPending; $result = $this->db->query("SELECT id FROM field_comments WHERE status=$status AND email='$email' ORDER BY created DESC LIMIT 1"); $comment_id = 0; if($result->num_rows) list($comment_id) = $result->fetch_row();
-
Thanks for posting- Looks good. We don't have anything like this yet, so I'm sure this'll come in handy!
-
How to troubleshoot: non-virtual folders returning PW 404?
ryan replied to MarcC's topic in General Support
It's quite a mystery. Can't say as though I've seen something like this before. It has me wondering if there is some mod_security setup or something else that is interfering with the usual behavior... that's the only thing I can guess, but I'll keep thinking. -
How to troubleshoot: non-virtual folders returning PW 404?
ryan replied to MarcC's topic in General Support
Marc is this server running Apache or some Apache clone? The reason I ask is that it's not behaving like Apache. ProcessWire should never get control of the request due to these two directives: RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d That basically says: "In order to give control to PW, the requested file or directory must not exist." So assuming it's actually Apache and it understands those directives, we have to look at why it's not associating that with what's actually on the file system. I would probably try adjusting the RewriteBase line to be "RewriteBase /". If that doesn't work, you might want to look at enabling the VirtualDocumentRoot line (at the bottom of the htaccess file). The 'nobody' permission should be okay. That's most likely the user that Apache is running as. You've got me curious please let me know what you find. -
You could also try turning of session fingerprinting from your /site/config.php. Fingerprinting keeps track of your IP and HTTP user agent, and destroys the session if either changes. That sounds like what's happening to you. /** * sessionFingerprint: should login sessions be tied to IP and user agent? * * More secure, but will conflict with dynamic IPs. * */ $config->sessionFingerprint = true; // change to false
-
I'm running 21k pages on one site right now, and no difference in speed than if it was running a dozen pages. Though of course, I'm not doing anything that loads all those 21k pages at once (I don't think that would even be possible).
- 12 replies
-
- 1
-
-
- performance
- page limit
-
(and 1 more)
Tagged with:
-
How to troubleshoot: non-virtual folders returning PW 404?
ryan replied to MarcC's topic in General Support
That's pretty bizarre. Have you tried another browser, just in case something is going on with the cache? Also, none of the URLs you mentioned have trailing slashes--try adding one (if you haven't already). Can you give us an "ls -al" of the piwik directory and the contents within it? I'm interested to see the permissions and what's in there. -
The $event->arguments is just an array of arguments that were passed to the function you hooked, in the order they were passed to the function. You can also retrieve them by name if you prefer, i.e. $event->arguments('page') would retrieve the argument named '$page'. In addition to being able to read these arguments, you can also change them if your hook is a "before" hook… letting you modify what ultimately gets sent to the function you are hooking. There's also $event->object, which is the object instance containing the function you hooked. So in the example from my previous post, $event->object would be $pages. That's probably not very useful, but when dealing with hooked methods on other things (like a Page or a PageArray) it might be exactly what you need. Lastly want to mention $event->return. If your hook is an "after" hook, then $event->return will contain the value returned from the function you hooked. Like with arguments you can modify this value if you want to. If you add a hook somewhere, and there isn't any function to hook, then you've just added a new function to that class. When someone tries to call that function, it'll call your hook instead. There are other things you can do with hooks too, like add properties to an object (rather than just methods) and entirely replace a function with your own. But these are less used things.
-
Thanks joshuag. The PageLinkAbstractor module has been expanded and renamed to LinkMonitor. I've been using it for a couple of weeks locally and still have a few bugs to work out, but overall I think it'll be a nice addition. Has anyone had a chance to try out the dev branch yet? I'm thinking about merging it into master here pretty soon, and just want to make sure I'm not the only one that's used it.
-
I think that's the first installation I've seen using the new Blog profile. Good to see.
-
One other thing about this module that's maybe interesting from a module development standpoint: It installs a page (/service-pages/), and the template for that page loads and runs the ServicePages module when it is viewed. So it installs the means to run itself, and it's not autoload. I might be wrong, but can't think of another module that does this, and maybe it's a good pattern. At least, I thought it was fun when building it. I've been thinking about building a module starter kit that includes skeletons for various types of modules and install/uninstall patterns (ready to build from), and this type of pattern would be one among a few others.
-
The recursive loop comes from your $p->save(); which is again triggering your pageSaved() hook, and continues doing so infinitely to a deeper and deeper level. There's probably a bunch of ways to solve this. But here's two really simple ways. First is to just set some landmark variable (we'll call it skipMe) so that your hook will know to skip over pages that it is creating itself. Your landmark variable (skipMe) doesn't need to be a PW field or anything, as you can make up any name/value on the fly and set it to a $page for temporary use like this. public function pageSaved($event) { $page = $event->arguments[0]; if($page->skipMe) return; $p = new Page(); $p->template = 'basic-page'; $p->parent = '/about/'; $p->status = Page::statusUnpublished; $p->title = "This is the pagename"; // set some landmark so pageSaved knows to skip this one $p->skipMe = true; $p->save(); } The next option would be to just have your $p->save(); skip over all hooks: $p->___save(); When you call the function name with 3 underscores in front of it, it does so without executing any hooks, thereby preventing the infinite loop. However, this may or may not be what you want, because it would also skip over any other Pages::save hooks that might be present.
-
Sounds like you may be beyond this need, but just wanted to mention those < > brackets are probably the most important ones to encode (for security), and one of the main reasons to use the HTML entities textformatter. But Textformatter modules are super-easy to create and make them do whatever you want. You can just copy /wire/modules/Textformatter/TextformatterEntities.module to /site/modules/TextformatterGazley.module. Then edit it and change the class name to TextformatterGazley and change the module's title (in the getModuleInfo function). Modify the format() function to do whatever you want. For instance, you could entity-encode and then just decode the < and > entities, if that was your need: public function format(&$str) { $str = htmlentities($str, ENT_QUOTES, "UTF-8"); $str = str_replace(array('<', '>'), array('<', '>'), $str); } Decoding those < and > entities is definitely not something to do with untrusted user input though.
-
Very nice, thanks for posting this! What do you think about putting this on GitHub so that it can be installed through the modules directory? I would do it myself, but have no way of testing LDAP, so don't think my GitHub account would be a good one to have it on. I also know that the original author (JimYost--my brother-in-law) is really busy at work and not likely to post or develop this further. But it seems like a pretty unique and great module, so would be great to have it as something more than a copy/paste, if/when you or someone else using it has time.
-
Pete's module code he posted seems to be a good way to do this. You might also want to add a little check to the buildUrl function/hook, just in case they haven't selected a make or model yet. // make sure a make and model are already selected if($page->make && $page->model) { // make sure $page->name isn't already in a "make-model-stocknum" format if(!preg_match('/^\w+-\w+-\w+$/', $page->name)) { $page->name = $page->make->name . '-' . $page->model->name . '-' . $page->stocknum; } } You can change the label that appears with the field by editing your template and clicking on the "title" field in the list. It'll pop-open a model dialog box where you can change the settings of that field specific to the context of that template. In your case, you would just change the "Title" label to be "Stock Number". And of course, you'd update the code examples above to refer to $page->title rather than $page->stocknum.
-
I haven't used the async attribute before. The info for it seems to suggest that it's only for "external" scripts, but doesn't clarify what they mean by "external." I would assume that to mean scripts that exist on another domain, but who knows, maybe they just mean scripts that aren't inline in the HTML? If it's not implying another domain, then it seems like an interesting possibility. Load order is pretty important for a lot of these scripts, so not sure we'd be a good case for it. Though there may be a few scripts we can do it with.
-
Awhile back, I made an Ajax API for querying pages in the admin via the ProcessPageSearch module. It is used by [for example] the PageAutocomplete Inputfield. I thought this capability would be useful on the front-end too, so this module brings it to the front-end as a page in your site that you can put wherever you want to. The way you use it is exactly the same as the one in ProcessPageSearch, but this one is a little more strict, given that it's publicly available on the front-end. By "more strict" I mean that you have to define what you want to allow in terms of input and output in the module's configuration. The web service takes it's query from GET variables in the URL and returns results in JSON format. It installs a page called /service-pages/ in your site, and you are welcome to move that page wherever you want. Here is the official page at modules.processwire.com: http://modules.processwire.com/modules/service-pages/ Once installed, you should view the /service-pages/ page that it installs because it outputs detailed instructions and examples on how to use it in your own projects. But here's a few excerpts from what you'll find on that instructions page: Input The /service-pages/ page can be queried with GET variables in the URL to return JSON-format results. The query string should follow a ProcessWire selector format ([field][operator][value]), but modified a bit for use in a URL query string. Here are a few format examples: Specify a single value: ?field=value Specify multiple fields and values to match: ?field1=value1&field2=value2&field3=value3 Specify multiple fields where at least one must match the value. Note use of "," rather than "|", something we had to settle for to make it work as a URL key: ?field1,field2,field3=value Specify one field with multiple possible values (it's fine to use "|" as a separator here): ?field=value1|value2|value3 Note that unlike regular ProcessWire selectors, multiple field=value sets are split with an ampersand "&" rather than a comma ",". Allowed Values The allowed values for field are set with the module configuration. You may also specify the following modifier keyword=value pairs: sort=[field] (Specify field name to sort results by) debug=1 (Enables debug mode producing human readable output) limit=[n] (Specify the max number of pages to return) start=[n] (Specify the result number to start with) include=hidden (Include pages that are 'hidden') Allowed operators The operator demonstrated by the "=" sign in the examples above may be replaced with any of the following operators in the query string: = Equal to != Not equal to < Less than > Greater than <= Less than or equal to >= Greater than or equal to *= Contains the exact word or phrase ~= Contains all the words %= Contains the exact word or phrase (using slower SQL LIKE) ^= Contains the exact word or phrase at the beginning of the field $= Contains the exact word or phrase at the end of the field As an example, this ProcessWire selector: template=property, body*=luxury, bedrooms>5, bathrooms<=3 ...would be specified as a query string to this web service like this: ?template=property&body*=luxury&bedrooms>5&bathrooms<=3 Allowed templates For security, the search will only be performed on pages using templates that are defined in the module's configuration. Output The returned value is a JSON format string in the following format (populated with example values): { selector: "title*=something, template=basic-page, limit=50", total: 2, limit: 50, start: 0, matches: [ { id: 1002, parent_id: 4525, template: "basic-page", path: "/test/hello/", name: "hello" }, { id: 1005, parent_id: 4525, template: "basic-page", path: "/test/contact/", name: "Contact Us" } ] } Each of the 'matches' values will also include all the fields you have specified to appear with the ServicePages module configuration. If an error in the query prevented it from being performed, a JSON string in this format will be returned: { errors: [ "Error message 1", "Error message 2 (if there was one)", "And so on..." ] } The web service honors user view permissions. As a result, if you are accessing this service from a superuser account, you are likely to get pages that others users may not see. Superusers get an "include=all" automatically, unless you override it with an "include=hidden". Returned field values The following field values will be returned for all matched pages: id (integer) parent_id (integer) template (string) path (string) name (string) Any other fields may be included from the module's configuration screen. Pagination To paginate, simplify add a "page[n]" url segment to the request URL, i.e. /service-pages/page2/?template=basic-page&sort=name
-
I guess I don't totally understand the issue here, as I've never had to wait for anything in real use. And I'm using a run-of-the-mill consumer grade internet connection. I recognize we've got a lot of small files to load (the modularity is intended), but I've never personally felt any load time drawbacks. And once loaded, of course they are then waiting in the cache, not needing to be loaded again. Perhaps it's more a matter of connection speed, but this is a web application not a front-end facing site where thousands of people might hit it at once. I'd consider it a best practice to minimize the quantity and size of loaded files on the front-end, but might consider it the opposite in an admin application like this, where modularity is far more important. If load time is an issue for anyone, I think we might do better to find ways to optimize the browser cache. For instance, can we send some cache control headers to reduce the 304 requests (or perhaps something like that). Though I'm also not against automated combining/minifying, if there are good opportunities to do it without side effects, and there is a tangible (not just tiny measurable) performance benefit to be found.
-
I almost always try to structure sites in a manner is consistent structurally and navigationally. I also think this is one thing that differentiates ProcessWire sites from some other CMSs (like Drupal), where the navigation structure is completely disconnected from the content organization -- it's maddening. So I think it's good to consider structure and navigation in the same process when possible. If you have a huge disconnect between the two, it's good to look at re-evaluating the structure. But I totally understand the need to have a custom menu in one place, or insert a page from a menu in another place, etc. Here's how I do it: When you need to have a navigation link in an existing structure, even though the page isn't in that structure, you can give it a placeholder. Create a field called "redirect_url" of type "URL". Create a template called "redirect" and add your "redirect_url" field to it. Then paste the following in your /site/templates/redirect.php file: <?php $session->redirect($page->redirect_url); Now whenever you need an extra navigation item somewhere in your structure, without the page actually being there, create a placeholder page using the "redirect" template. Put in the URL to the page you want it to go to. When the page is viewed, it'll end up where it's supposed to go. If you want to avoid the 301 redirect, you can also just update your navigation output code to give preference to a redirect_url field when it exists. And it'll use redirect_url when it's populated, and url when it's not: <a href="<?=$page->get('redirect_url|url')?>"><?=$page->title?></a> When you need to create a custom menu that has nothing to do with the site's structure, use a page reference field. For instance, lets say you wanted to create a "footer_links" navigation. You'd create a new multi-page reference field called "footer_links". Choose "Page List Select Multiple" as the Input field for it. Add this field to your homepage template. Edit your homepage and use that field to select the pages, anywhere in your site, that will be in the footer links navigation. Then output them like this: <ul id='footer_links'> <?php foreach($pages->get('/')->footer_links as $item): ?> <li><a href='<?=$item->url?>'><?=$item->title?></a></li> <?php endforeach; ?> </ul> Let me know if I've answered consistently with what you were looking for, or if you are trying to do something else?