Jump to content

ryan

Administrators
  • Posts

    16,770
  • Joined

  • Last visited

  • Days Won

    1,530

Everything posted by ryan

  1. Cloning seems to work for me. I did recently commit some fixes to cloning, which I think was in 2.3.7, so it sounds like you have the current version. Any other factors that accompany the pages you are trying to clone? For example, are you using any multi-language fields or language support? Are there any 3rd party modules? Do the pages have children or no children?
  2. It's possible for it not to work on an Apache server too, if unzip isn't installed (which would be unusual) or if exec() is disabled (more common). There's also a chance unzip just isn't in the executable path on your server. You might see if you can locate where unzip is on the server.. it would usually be /usr/bin/unzip or /usr/local/bin/unzip. If you can login via ssh, you might be able to find it by typing "which unzip". Anyway, once you know where it is, you can take this line from /site/config.php: /** * uploadUnzipCommand: shell command to unzip archives, used by WireUpload class. * * If unzip doesn't work, you may need to precede 'unzip' with a path. * */ $config->uploadUnzipCommand = 'unzip -j -qq -n /src/ -x __MACOSX .* -d /dst/'; and prepend it with the server path: $config->uploadUnzipCommand = '/usr/bin/unzip -j -qq -n /src/ -x __MACOSX .* -d /dst/';
  3. Actually you should be able to use "children.name=tarjetas", but I tested it out here and it behaves the same as "parent.name=tarjetas", so that is a bug. Looks like this is the first instance I've seen of needing to use something other than children.count. I've now fixed it, but am doing a little more testing locally before committing to dev.
  4. asmSelect doesn't support keyboard input. How are you typing in numbers?
  5. There are limits on field options no matter what route you take. Even a plain Select inputfield has limitations, in that it can't scale to thousands of items. The best bet is to find the solution that can select the pages you need to be selectable, then determine which of the available inputfields to use. There are lots of inputfield options in part because they aren't always interchangeable... each has their strengths and weaknesses.
  6. Part of the goal with rich text editors (and LMLs even more) is to place limitations upon the input in order to maintain quality and consistency. ProcessWire's TinyMCE and CKEditor come configured to focus purely on portable and semantic markup. Once you start introducing non-semantic things in the markup like inline styles, colors, arbitrary font sizes, etc., then your content is no longer semantic or portable. It becomes essentially anchored to your current site design (if you are even that lucky with the client). You'd likely have to go back and make edits to all those fields the next time the site is redesigned. An even bigger problem is that when you give clients the tools to do these kinds of things, they start to get creative and think of it as an art project. But they blame you 1-2 years later when their site no longer looks professional. CMS control of style in text output ensures degradation of consistency and quality of output over time. For these reasons, you usually want to keep your content management tools (and especially rich text editors) focused purely on semantics of content, and as far from style as possible. This is one reason why I think front-end inline editors are a bad practice, as they keep the focus off the semantics of the content and on the subjective aspects of how it fits the area. Let all the style aspects be handled the site designers, in your front-end CSS stylesheets that accompany the site's design. If you still want to inject style, Hanna code is not a bad way to go because it does at least introduce some separation of concerns. It still leaves the content semantic, even if the underlying Hanna code isn't. If the site is for your own use and you are okay with the compromises, then both TinyMCE and CKEditor can be configured to let you do nearly anything you want. I'm not an expert on how to configure them that way, but if you look at the demos at either site, they have "all options enabled" configurations you can see and these configuration options can be duplicated in PW. Lastly, a plain textarea field (no rich text editor) on it's own also works well for just regular HTML input. This is what I use when I do need something that lets me copy and paste HTML directly, though it's something I'd only do on a site where I'm the only admin/editor (at least for that particular field).
  7. No, it's also more efficient (technically faster) on the front-end. It's possible, but you'd have to go in and add them directly in MySQL using PhpMyAdmin or the like, and update the module's code to recognize your new field. Probably not. While the database could handle millions of rows, the admin side won't be able to handle displaying millions of rows in the same page editor. It would be the same issue as with using a repeater, at least from the admin display aspect. Though this solution could technically serve a lot more rows than a repeater could. It would not be as scalable as using pages, simply because everything around pages is already designed in consideration of scale (limits, pagination, selective loading of fields, etc.). Pages are certainly more resource intensive, but those resources go towards making them scalable.
  8. 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.
  9. 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";
  10. 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.
  11. 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.
  12. "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.
  13. 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.
  14. 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.
  15. 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.
  16. 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.
  17. 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.
  18. 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.
  19. 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.
  20. 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?)
  21. 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>"; }
  22. 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.
  23. 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.
  24. This is significantly more scalable and resource friendly than repeaters. It's directly connected to a single DB table without any other overhead.
×
×
  • Create New...