Jump to content

ryan

Administrators
  • Posts

    16,714
  • Joined

  • Last visited

  • Days Won

    1,515

Everything posted by ryan

  1. When the need is there for separate DB configurations and something more than config-dev.php, I've done it like this in my /site/config.php file: switch($_SERVER['SERVER_NAME']) { case 'localhost': // set database settings for localhost break; case 'dev.domain.com': // set database settings for staging server break; default: // set database settings for production server } You should give preference to SERVER_NAME in this case (over HTTP_HOST) just because HTTP_HOST is coming from the client rather than the server (open to tampering). Though it doesn't really matter as long as your last "default" condition assumes the production server.
  2. If you don't need the page to be saved when the button is clicked, then I think the route you are taking is fine. If you did need the page to be saved, then you'd want your button to be a submit button, and a second (save) hook to be called after the ProcessPageEdit::processInput and to silently do its thing (no redirect). Another route you could take is to setup a separate page with a template that does what you want, and then have your button link to that instead. But the way you've done it is already more compartmentalized (less parts to consider) so I wouldn't change it unless it creates issues with other modules hooking into ProcessPageEdit at some point down the road (which is possible). One issue you probably want to fix here though is the potential for XSS: $href = $this->config->urls->admin.'page/edit/?id='.$this->input->get->id.'&e=1'; Taking a variable directly from $_GET or $input->get and putting it in output (unsanitized) is always dangerous. You'd want to do this: $id = (int) $this->input->get->id; $href = $this->config->urls->admin."page/edit/?id=$id&e=1"; or better, yet this: $id = (int) $event->object->getPage()->id; $href = $this->config->urls->admin."page/edit/?id=$id&e=1";
  3. To match a partial word in the middle of it, you'd need to use a non-fulltext-indexed search. That's because fulltext indexing indexes full words, not parts of words... it can only match full words or words beginning with some text. To use a non-fulltext-indexed search, use the %= operator rather than the *= operator. This highlights a core difference between *= and ~=. The *= operator is matching an exact word or phrase that begins with your term. The ~= operator is matching full words, but they can be matched no matter where they appear in the text / in any order. The %= operator behaves very much like the *= operator except that %= can match in anywhere in-between words too, not just words/phrases that begin with something. So long as the $user->language is set to the language you intend to search in, it will give preference to that language in performing the search.
  4. This is a good way to go, and exactly what I do for predefined settings like required image dimensions and such. What you set in _init.php is for runtime use of your site's template files, and probably nothing beyond that. These variables are good for initializing placeholders that you'll be outputting in your _main.php (or whatever your appendTemplateFIle is called). This sounds like overkill to me, though of course use what works best for you. But you have a couple more options to consider: Use session variables, especially when you want the value to still be present and available on not just the current request, but subsequent ones (from the same user) too: // do this $session->set('my_variable', 'my_value'); // then retrieve it from anywhere (and at any later request) like this: $my_value = $session->get('my_variable'); Set an API variable: // do this wire('my_variable', 'my_value'); // then retrieve it from anywhere like this: $my_value = wire('my_variable'); Whichever route you take there, if you've got a lot of related values to set you might want to bundle them all into an array, so that you only need to set 1 session, API or config variable.
  5. "id!=$config->adminRootPageID|$config->trashPageID|$config->http404PageID", That part above probably isn't necessary in the selector. The "template!=admin" and "has_parent!=$config->adminRootPageID" will probably cover everything you need (assuming you want admin pages excluded from last modified listings). While you could exclude the 404 page, I'm guessing that's one that probably rarely if ever ends up in a modified list anyway.
  6. The export profile module is 2.3 compatible, but not when it comes to multi-language sites using the core LanguageSupport modules. That's something that's been on my to-do list for awhile. I just don't use the Profile Export module often enough, but hope to update that a little after 2.4 is released.
  7. Fay, I noticed your last two screenshots contain a plain HTML field with raw visible HTML tags. Is that what you intended, or is this supposed to be a rich text field? I ask because it's a little unusual to edit raw HTML like that (that's what TinyMCE and CKEditor are great for, or an LML like Markdown or Textile). Always respect for editing raw HTML, but it's not something I see very often, so just wanted to make sure there's not some JS error or something blocking the rich text editor.
  8. Template caching is language aware (and it includes the language as part of the cache file's id), but you'd have to have some aspect of the request determine the language before rendering the page. Otherwise there's no way to connect that cache file with the request. The simplest way to do that is to use the LanguageSupportPageNames module, to ensure that your homepage (for example) has a different URL for each language. If you are determining language from the hostname (i.e. en.domain.com, it.domain.com, etc.), then you'd have to have a before(Page::render) hook that sets the $user->language based on the hostname. I'm not sure what method you are using to determine language, so let me know and I can give you a better example.
  9. ProcessWire requires sessions, so it's not something you have to install. Though the database sessions module is an optional install. But $user->isLoggedin(); has to do with the current user only. It cannot tell you if other users (separate from the current session) are logged in or not.
  10. Also look into using RSS feeds (via MarkupRSS and/or MarkupLoadRSS) as these are one of the most common ways for sites to share content.
  11. These should also work (on dev): // save directly from page object $page->save(array('quiet' => true)); // save just 1 field from page object $page->save('myfield', array('quiet' => true)); When quiet mode is set, the modified date is set to whatever is specified in the page. Meaning, the modified date is not updated unless you change it yourself. Quiet mode also lets you modify the modifedUser and createdUser for the page, if you want to. These are two properties you can't usually modify, but quiet mode lets you do it.
  12. Soma, glad you found the source of the HTML document. Regarding the saveReady, I think it may be problematic to try and save a page in there because it's going recursive. Calling a save() from saveReady triggers another save and thus another saveReady, and so on. I don't yet know why its working with some hooks and not others, but wanted to point out the potential for an infinite loop there. When recursion is involved sometimes things can get weird, or at least hard to debug. If it's possible to move it all to a saved() hook, that may be less prone to issues. While there would still be recursion there, at least it wouldn't interfere with the save order. Technically what you are trying to do should be possible by preventing an infinite loop from within your hook (which I think your template check is doing), but this is one of those scenarios that may require more abstract jumps and debugging than is worth the effort, at least if you can accomplish it in any simpler fashion.
  13. Soma, I'm not sure I follow everything here and agree it all sounds pretty odd. First things first, I think it'd be good to figure out where the HTML4 document is coming from. The only thing I can guess is TinyMCE is saving it this way, and you are just discovering it as a result of this debugging session? It almost looks to me like the HTML contents of TinyMCE's iframe window. If you still don't know where this is coming from, then I think we need to focus in on that cause it seems really odd (PW does not generate any HTML documents like that). What other modules are installed and running? Is it possible it's being added by some mod_security type Apache module (automatically adding an <html> wrapper around content it sees as HTML in a POST request?)
  14. Here are some API additions to the dev branch, primarily for WireArray/PageArray/etc. I've found these very handy lately, and would have on almost any project I worked on, so decided they'd add value to the core. I'll add these to the cheatsheet once 2.4 replaces 2.3, but for now, here they are. The examples here use PageArray, but note that these API additions apply to any WireArray derived type, not just PageArray. WireArray::implode() Implode all elements to a delimiter-separated string containing the given property from each item. Similar to PHP's implode() function. Usage: $string = $items->implode([$delimiter], $property, [$options]); Arguments: $delimiter - The delimiter to separate each item by (or the glue to tie them together). May be omitted if not needed $property - The property to retrieve from each item (i.e. "title"), or a function that returns the value to store. If a function/closure is provided it is given the $item (argument 1) and the $key (argument 2), and it should return the value (string) to use. [$options] - This argument is optional. When used, it's an array with modifiers to the behavior: skipEmpty: Whether empty items should be skipped (default=true) prepend: String to prepend to result. Ignored if result is blank. append: String to prepend to result. Ignored if result is blank. Examples: $items = $pages->find("template=basic-page"); // render all the titles, each separated by a <br>, for each page in $items echo $items->implode('<br>', 'title'); // render an unordered list of each item's title echo "<ul><li>"; echo $items->implode('</li><li>', 'title'); echo "</li></ul>"; // same as above, but using prepend/append options, // this ensures no list generated when $items is empty echo $items->implode('</li><li>', 'title', array( 'prepend' => '<ul><li>', 'append' => '</li></ul>' )); // same as above, but with all items now presented as links // this demonstrates use of $property as a function. note that // we are also omitting the delimiter here as well, since we don't need it echo $items->implode(function($item) { return "<li><a href='$item->url'>$item->title</a></li>"; }, array('prepend' => '<ul>', 'append' => '</ul>')); WireArray::explode() Return a plain array of the requested property from each item. Similar to PHP's explode() function. The returned PHP array uses the same keys as the original WireArray (if that matters). Usage: $array = $items->explode($property); Arguments: $property - The name of the property (string) to have in each array element (i.e. "title"). You may also provide a function/closure here that should return the value to store. When a function/closure is used it receives the $item as the first argument and the $key (if needed) as the second. Examples: // get an array containing the 'title' of each page $array = $items->explode('title'); // get an array containing the id, url and title of each page $array = $items->explode(function($item) { return array( 'id' => $item->id, 'url' => $item->url, 'title' => $item->title ); }); WireArray::data() Store or retrieve an arbitrary/extra data value in this WireArray. This is exactly the same thing that it is jQuery. I've personally found this useful when building search engines: the search engine can store extra meta data of what was searched for as a data() property. Then any other functions receiving the WireArray/PageArray have access to this additional info. For example, the search engine portion of your site could populate an array of summary data about what was searched for, and the render/output code could render it to the user. Usage: // Setting data $items->data('key', 'value'); // Getting data $value = $items->data('key'); // Get array (indexed by key) of all data $values = $items->data(); Arguments: The above usage section explains all that's needed to know about the arguments. The only additional comments I'd make are that 'key' should always be a string, and 'value' can be anything you want it to be. Example: function findSkyscrapers() { $floors = (int) wire('input')->get->floors; $year = (int) wire('input')->get->year; $items = wire('pages')->find("template=skyscraper, floors=$floors, year=$year"); $items->data('summary', array( 'Number of floors' => $floors, 'Year constructed' => $year )); return $items; } // the render function can focus purely on output function renderSkyscrapers($items) { echo "<h2>You searched for:</h2>"; // render the summary of what was searched for foreach($items->data('summary') as $label => $value) { echo "<p>$label: $value</p>"; } echo "<h3>Skyscrapers found:</h3>"; // note use of new implode() function, though a foreach() would be just as well here echo $items->implode(function($item) { return "<p><a href='$item->url'>$item->title</a></p>"; }); } WireArray::and() WireData::and() Return a new copy of the WireArray with the given item(s) appended. Primarily as a syntax convenience for various situations. This is similar to jQuery's add() and andSelf() functions, but I've always felt "add" implied adding something to the original rather than creating a new combination, so went with "and" in this case. The term "and" is actually a reserved word in PHP, so you can't usually have a function named "and()", but through the magic of hooks, ProcessWire can. This function should reduce the instances in which you'd need to do "$a = new PageArray();" for example. Usage: // create a new WireArray with $items and $item (appended) $myItems = $items->and($item); // create a new WireArray with $items and $moreItems (appended) $myItems = $items->and($moreItems); // create a new WireArray with $items and $item (prepended) $myItems = $item->and($items); // create a new WireArray with $item and $anotherItem (appended) $myItems = $item->and($anotherItem); // create a new WireArray 4 items $family = $pappa->and($mamma)->and($brother)->and($sister); Examples: // generate breadcrumb trail that includes current page foreach($page->parents->and($page) as $item) { echo "<a href='$item->url'>$item->title</a> / "; } // check if page or its children has a featured checkbox if($page->and($page->children)->has("featured=1")) { echo "<p>Featured!</p>"; }
  15. Thanks for your message and PR. This was fixed yesterday morning as soon as I saw it. I can only guess that I was still getting an older cached version of the JS file when testing this change.
  16. Lets say you've got the page /family/ that has everything below it you want protected by a login. Create a new role (in Access > Roles), call it whatever you'd like but maybe "family" is a good name. For permissions, check the box for Page View, and that's it. Create one or more new users for your family, and give them the family role. In your admin edit the template used by your /family/ page (let's say it's also called 'family') and go to the 'Access' tab. Check the box to enable access control. For view access, check the box for "family" but not for "guest". Also when editing your family template, for the section on "what to do when a user doesn't have access", choose the box to redirect them to the login form. Or if you want your own custom login form, you can later change this to redirect to a custom URL that contains your login form. In your /site/config.php file, see the section on the "pagefileSecure" option and determine if that is something you will want to use or not. By default is is off.
  17. This is significantly more scalable and resource friendly than repeaters. It's directly connected to a single DB table without any other overhead.
  18. That usually means that 1) your roles don't permit you publish access; or 2) not all required fields are filled in.
  19. Actually either syntax should work here. The $users->add('name'); function is a valid way to create a new user. Though the $u->of(); and $u->save(); immediately after your add() aren't necessary. The $users->add() syntax is newer though, so may not be present in past versions of PW.
  20. Perhaps FieldtypeFloat could temporarily switch the locale back to C whenever it needs to operate on it, then switch it back.
  21. ryan

    CollagePlus

    Are you using CollagePlus on it's own or the CollagePlus module in ProcessWire?
  22. It sounds like you are talking about from the API side. You can work with repeaters just like any other pages, but you just have to know where to find them. Your repeater items are going to be using a template with the name of your repeater field pepended by "repeater_". So if you've got a repeater field called "slideshow", then pages within that repeater are going to be using the "repeater_slideshow" template. As a result, you can query them like this: $pages->find("template=repeater_slideshow, ..."); Repeaters are kept in the admin structure, so if your code needs to do it's thing on the front-end of your site, then you'll also want an "include=all". Note that unpublished+hidden repeaters are considered unpopulated "ready" pages, so you can safely skip over them.
  23. Actually, you can do this on the dev branch. Lets assume that cities are children of countries and that is reflected in your page structure (i.e. /countries/france/paris/). Create your 2 page fields (country and city), and configure 'country' as a single page field with "parent" set to "/countries/". Next, for the "city" field configuration, use the "Custom selector to find selectable pages", present on the "input" tab. In that field, enter "parent=page.country". Save and try it out. This works with select, selectMultiple and asmSelect fields (and possibly others), though not yet with checkboxes, radios or PageListSelect.
  24. Hard to say for sure. But those 4 unpublished records were most likely intentional 'ready' pages. This quantity is defined in your repeater field settings (details tab).
×
×
  • Create New...