Jump to content

ryan

Administrators
  • Posts

    16,715
  • Joined

  • Last visited

  • Days Won

    1,517

Everything posted by ryan

  1. Every site needs a 'root' page (homepage) but it doesn't matter what you do with it. I think all you need to do is just copy whatever is in your index.php file and paste it into the home.php file. And then get rid of your index.php file, because it will be home.php instead. Of course, you can also add/delete fields from the home template as needed.
  2. This is intended as an installation profile, so not something that is ready to plug into an existing installation. Though you could certainly copy the templates, install the BlogAPI module, and re-create the fields and pages it uses in an existing install. Though I do plan to make the BlogAPI module installable, so that it can install everything needed by the profile into an existing site. But going to wait till the profile is pretty well nailed down before doing that-- it shouldn't be far off. Also an update about the profile: the next version is going to be running on the Skeleton responsive framework instead. I'm just finding that framework to be a little better for the blog profile. However, I'll still include the Foundation template and CSS file as optional, so that you can still use the Foundation version if you prefer it.
  3. Thanks, I didn't realize that, I will update it. I'm not sure I've ever actually seen it written like kB (looks like a mistake doesn't it?) but I'd rather it be correct than pretty.
  4. I recommend using either Textile or Markdown if you need to support this type of stuff in your image/file descriptions. For instance, in Markdown you would make bold text **like this** You'll need to run your image/file descriptions through Textile or Markdown before outputting them. So can do that like this. I'll use Markdown in this example since the module is already in the core. $markdown = $modules->get('TextformatterMarkdownExtra'); $description = $page->image->description; // your image description $markdown->format($description); echo "<p><img src='{$page->image->url}' alt='' /> $description</p>"; We'll likely add internal support for these Textformatters for image/file descriptions in the near future, so that you don't have to do the above if you don't want to.
  5. I'm not sure I follow 100%, but it sounds to me like the next step you need to take is add the templates in ProcessWire. If your files are already ready-to-go in your /site/templates/ directory, then you can go to Setup > Templates > Add New Template. Check the box next to all the ones you want to add (of course, leave out your header/footer includes since those are partials rather than actual templates). Then create your new pages using those templates you've added as appropriate. How you structure them is up-to-you. ProcessWire gives you a tree structure which you can push in any direction you want to. Think of your pages as a family tree and decide what should be "children" of another. With regard to access control, you can configure this on a per-template basis. You can also leave it off, which will make each page using a given template inherit access control settings from the nearest ancestor page that has a template defining access (often the homepage).
  6. Actually I think that the first issue has to do with your MySQL collation. Right now I think it would be utf8_general_ci which sorts (and I think text indexes) as if it were all ASCII, sans accents. This is often desirable, but not in your case. You'd want to change the collation to something like utf8_unicode_ci or a more language-specific version if available (like utf8_swedish_ci). Btw, the "ci" part means "case insensitive". If you want case sensitivity, then you'd want the "cs" version, like utf8_unicode_cs. To change the collation you'd want to edit your database in a tool like PhpMyAdmin. Find the tables for the fields in question: field_title, field_translation, field_definition. Edit the 'data' column of those tables. Change the collation from utf8_general_ci to utf8_unicode_ci. Rebuild the index for each by running a table repair. You can do this in PhpMyAdmin by editing the table, clicking the "operations" tab and clicking the "Repair" link at the bottom. Once you complete this, I think that you should get the behavior you wanted with regard to the matches and sorting. Regarding your second question, I'm a little confused on this one because you are searching for "dom" but wanting it to match "hus"? Obviously that's not possible. But what I think you are wanting is for it to match "dom" by itself rather than in the middle of other words and such... ensuring that your "dom" definition (that contains "hus") comes up a lot sooner than it currently is? If so, you need to use the ~= operator in your search rather than %=. Because %= is a non-indexed (LIKE) search, it'll match terms in the middle of words. Whereas ~= will only match full words. However, ~= is an indexed search and MySQL fulltext indexes only work with words of 4 characters or more by default. But if you have control over your server environment, this is an easy fix to make it support fewer characters. Btw, when you don't specify a "sort=" in your selector, and your selector searches text using either *= or ~=, the sort will be by relevance of the terms searched.
  7. ryan

    Twig

    Porl, tested out here and seems to work great! Thanks for your work with this. I did run into an error with the paths during installation, though not sure others will as it might have been user error on my part. However, I recommend updating the way reference paths. Don't bother with creating $this->dirname. Instead, do this: // replace this require_once $this->dirname . '/Twig/Autoloader.php'; // with this: require_once $this->config->paths->PageTwig . 'Twig/Autoloader.php'; // replace this $loader = new Twig_Loader_Filesystem($this->dirname . '/../../views/'); // with this $loader = new Twig_Loader_Filesystem($this->config->paths->templates . 'views/'); // replace this array('cache' => $this->dirname . '/../../assets/cache/twig/', // with this array('cache' => $this->config->paths->cache . 'twig/', Also some questions/comments about this: /** * initialises each field of $page. this is overkill but can be used if you don't want to keep * adding individual fields to the controllers. */ function twig_init_fields() { foreach ($pages->fields as $field) { $twig_vars['page']->$field = $page->$field; } } I don't think that your current twig_init_fields() function will work, because the $pages variable is out of scope. Besides, I think you wanted that to be $page instead? If so, you'd want to use wire('page') since $page would also be out of scope in that function. But even if that's the case, I'm confused because when you set $twig_vars['page'] = $page; shouldn't you then be able to already access all the properties of $page? For the same reason, are these lines in twig-test.php even necessary? $twig_vars['page']->body = $page->body; $twig_vars['page']->title = $page->title; It doesn't seem like they should be. But then I tried commenting out the first one for $page->body; and got an error about Page::body() being a non existing function. So it looks like Twig is doing an isset($page['body']); and if it returns false it's trying to call $page->body() as a function. Now it all makes sense. I think I will update the Page::__isset() function to return true when a valid field for the page is requested. That would solve this and prevent you from having to initialize any variables in this manner. And make PW more template-engine friendly, as I'm assuming others may work like this too. Just tried updating Page::__isset() and it does seem to resolve it. Btw, the reason that you wouldn't want to do something like twig_init_fields() is that it would cause all of the page's data to be loaded, regardless of whether it would be used. This would cancel the benefit of PW's on-demand/selective data loading. Your module has me wondering if it wouldn't be a lot simpler for people to use if the Twig parsing happened automatically on the template fields without them having to delegate views, setup $twig_vars, include twigdefaults.php, or call $page->twig->render manually. What if your /site/templates/*.php could just be your Twig views, ready to go? I'm thinking it may be possible with something like this in an autoload module: public function init() { $this->addHookBefore('TemplateFile::render', $this, 'hookRender'); } public function hookBeforeRender($event) { $templateFile = $event->object; $filename = $templateFile->filename; // use some condition to know which templates should use Twig // here we just use filenames that start with "twig_", but might be more elegant to configure which // templates use twig in the module configuration or something if(strpos($filename, 'twig_') !== 0) return; // init twig require_once $this->config->paths->PageTwig . 'Twig/Autoloader.php'; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem($this->config->paths->templates); $twig = new Twig_Environment($loader, array('cache' => $this->config->paths->cache . 'twig/', 'auto_reload' => true)); // substitute a pre-defined placeholder file to replace the original template file // so that TemplateFile::render() is actually rendering our placeholder instead: $templateFile->setFilename($this->config->paths->PageTwig . 'placeholder.php'); $templateFile->set('twig_filename', $filename); // original template filename $templateFile->set('twig', $twig); // twig instance } Then the contents of the placeholder template: /site/modules/PageTwig/placeholder.php <?php $twig_vars = Wire::getAllFuel()->getArray(); echo $twig->render($twig_filename, $twig_vars); I haven't tried this yet, but I think it may work. If I get a little more time here in the next day or two to try this stuff rather than just write about it, I'll definitely give it a try unless you get to it first.
  8. From both a security and collaboration standpoint, I have a strong preference for pulling changes where they need to be made, rather than having them pushed from a dev server (export/import). I think you'll like where we plan to go with import/export of field and template data. Especially the copy/paste or file JSON option (which was in PW1 for fields at least), because it doesn't require you to be running a web server to import from. You can develop these things offline on your dev server, then export what you want, take it to your other/live server and paste in the JSON (or upload JSON file) and it re-creates them. PW1 didn't support using the option for modification of existing items (just for creating), but it's certainly feasible to provide the option. When it comes to pages, the same concept applies but is a little more complex given the diverse nature of page data that might include page references, file-based assets and so on. For example, with files/images, we can't reasonably encode those in JSON files and import elsewhere, so the dev server would need to be able to talk with the live server via a web service and pull the assets individually.
  9. I always develop in a subdirectory and usually launch to root. While Page Link Abstractor is one way to resolve that, an even simpler way is to do a search/replace on your DB dump file before importing it to your live server/root installation. I use TextWrangler (free version of BBEdit), but any quality plain-text editor should work. So lets say you were developing a site locally in /subdir/ and you wanted to update all the /subdir/ links to be / (root) instead: Search for: ="/subdir/ Replace with: ="/ This should cover all <a> and <img> tags, like <a href="/subdir or <img src="/subdir.
  10. The LanguagesPageFieldValue (and getLanguageValue function) are only applicable to multi-language fields. The only multi-language fieldtypes there are at present are TextareaLanguage, TextLanguage and PageTitleLanguage. Language alternate fields are an entirely different thing. It is nothing more than one field substituted for the other. For instance, 'image_de' would be substituted for 'image' when the user's language is 'de' and 'image_de' is populated. That's all there is to it. There aren't any other classes or functions to think about behind the scenes with language alternate fields. With language alternate fields 'image' and 'image_de', if you don't want fallback of 'image' to 'image_de' to occur when 'image_de' is populated and the user's language is 'de', then turn off output formatting, or retrieve the value with $page->getUnformatted('image'); Your example was trying to retrieve the value in 'de' regardless of the user's current language. So if that's what you are trying to do, then just access 'image_de' directly, i.e. $img = $page->image_de; or a non-language specific version: $img = $page->get('image_' . $user->language->name);
  11. That's correct. But note that these language alternate fields can be used with any fieldtype. So there's not really any reason to use them with TextLanguage, TextareaLanguage or PageTitleLanguage. They are an alternate way of doing multi-language fields.
  12. ryan

    Twig

    That's great if Twig is keeping track of knowing when to clear cache files. I see no problem with putting them in /assets/cache/twig -- that seems like the best place. I look forward to checking out your implementation!
  13. Here's the next version of the Blog Profile. This one incorporates the simpler structure I mentioned earlier, exactly as outlined. Please let me know how it works for you. To install, download a fresh copy of ProcessWire and replace the /site-default/ directory it comes with, with the one in the attached zip: blog-site2.zip Thanks, Ryan
  14. ryan

    Twig

    Definitely interested--keep it up! Regarding cache, I'm assuming it creates compiled templates and it's the PHP code that it's caching, not the content? If that's the case, there's not much use in trying to hook into PW's cache timing because it's all for output caching. You'd need something that can tell when a template file or template settings have changed and clear the cache then. PW has the ability to store dynamic info with each template, and I think we'd need to keep track of the file modification time for each template file, as well as the template modification time. Then when it sees that the file (or template) modification time is newer than the one saved with the template, it would clear the cache. Not sure how to do it just yet, but think we can figure it out. Let me know if this sounds consistent with what would be needed to you?
  15. I have the next version ready. I just need to export the profile and double check it all works. I hope to be able to post it later today after getting through some client work.
  16. Good points. The #1 idea sounds interesting and I like where you are going with that, though I don't think it's safe to consider the meta data independent from the content to the point where it would be safe to version them separately. The recorder modes (#2 & #3) would be great if it weren't for the issue of primary keys you mentioned, but maybe there are places where it could still work. I think that anything that involves merging two versions of the same site has to treat the other's data as totally foreign. Things like IDs have to be thrown out unless you are giving all ID generation authority to one or the other. Personally, I have never seen this as a particular problem to be solved because I've never seen the ability to do it, never expected to be able to, and not sure I could ever trust it if it existed. Nevertheless, I'm enthusiastic about exploring the possibility. But I'd be scared to death of having to provide support for such a feature. Something that I've got a higher comfort level with are specific import/export tools. For instance, a tool that enables me to connect my PW install with another, and browse the fields, templates and pages. Then I can click on "import" and have that field, template or page(s) created on my system too. If there's some matter of meta data to be resolved (like a new page reference with non-existing parent), then I know it then and there and can adjust my import sequence accordingly. If I'm modifying data rather than importing, then I can have the opportunity to see and confirm what's going to happen before it takes place. If we're talking about going between two servers that can't talk to each other, then copy/paste of JSON data from one to the other in the developer's browser is another way to accomplish it. This process seems more supportable because the individual site developer still has some ownership over what's happening.
  17. It sounds like you are triggering the language alternate fields. Assuming you have the LanguageSupportFields module installed, it'll be looking for any field names that end with a language name, like "_en" in "header_image_en". If it finds another field that has the same name, but no language (like "header_image"), then it assumes your "header_image_en" field is a language alternate field. Meaning, it'll substitute that field for "header_image" when it sees that the user's language is "en".
  18. Any modules that extend: Inputfield, Process or ModuleJS will auto-load their CSS/JS files if they have the same name as the module and appear in the same directory. However, in order for that to work, their init() method has to be called. So if your module extends one of those, and has an init() method, then make sure to call the parent init() method: public function init() { parent::init(); // ... then your code }
  19. I'm not sure that the W3 validator is picking it up right either? Seems like it is showing the whole thing as double entity encoded. Also tried loading in Safari, and it can't seem to read the feed correctly either. Firefox seems okay. Definitely something unusual going on with this feed, but I am not familiar enough with this particular format to know what's wrong. W3 validator isn't helping much since it's seeing the whole thing as double entity encoded.
  20. ryan

    VetsNet

    Nice work DaveP. I wish our vet had a nice, clean and responsive site like this. (we have 3 cats)
  21. Welcome to the forums abe.izar. Seems like they should make json_encode at least attempt to typecast an object to a string (which would convert to IDs here). Maybe I can update wireEncodeJSON (a front-end to json_encode) do that. However, if you really want to export pages and all their data to JSON, here's how you can do it: function pagesToJSON(PageArray $items) { $a = array(); foreach($items as $item) { $a[] = pageToArray($item); } return json_encode($a); } function pageToArray(Page $page) { $outputFormatting = $page->outputFormatting; $page->setOutputFormatting(false); $data = array( 'id' => $page->id, 'parent_id' => $page->parent_id, 'templates_id' => $page->templates_id, 'name' => $page->name, 'status' => $page->status, 'sort' => $page->sort, 'sortfield' => $page->sortfield, 'numChildren' => $page->numChildren, 'template' => $page->template->name, 'parent' => $page->parent->path, 'data' => array(), ); foreach($page->template->fieldgroup as $field) { if($field->type instanceof FieldtypeFieldsetOpen) continue; $value = $page->get($field->name); $data['data'][$field->name] = $field->type->sleepValue($page, $field, $value); } $page->setOutputFormatting($outputFormatting); return $data; }
  22. Alan the $comment->page will only point to the actual comment's page if the comment was retrieved with FieldtypeComments::findComments. Part of what that function does is populate the appropriate $page variable to all the comments it finds. However, you can still get it even if you don't have the latest PW or aren't using that findComments function: $page = wire('pages')->get($comment->pages_id);
  23. The PageLinkAbstractor is also a 3rd party module, and not one that I would try to build around at all. If something doesn't work with that module, then I would just say the two are not compatible with each other. I don't think many people are actually using that PageLinkAbstractor module anyway. I don't personally use it. If I've been developing a site in a subdirectory and then launch it to the root on another server, I just do a simple search+replace on the DB dump file, using a text editor (TextWrangler/BBEdit) replacing "/subdirectory/" with "/". However, this is something that I do plan to add core support for. The plan is that FieldtypeTextarea will encode local links to IDs like {123} when saving, and then unencode them back to URLs at runtime. We can collaborate on making everything work together when the time comes. I think I understand the problem you mentioned with a link created in TinyMCE being a static link in the language of the user making the edit. Would it be possible to just disable the URL parsing when the user is inserting a link? if(wire('process') == 'ProcessPageEditLink') { // don't parse URLs } else { // do parse URLs } The point of the above is so that the URL is always stored in the default language. Then hook into FieldtypeTextarea::formatValue and have it hunt down and replace them with the current language specific version, at runtime. I'm not so familiar with how the language localized URL module works, so this is based on guesses, but it might work something like this: public function init() { $this->addHookAfter('FieldtypeTextarea::formatValue', $this, 'hookFormatValue'); } public function hookFormatValue(HookEvent $event) { $language = wire('user')->language; // no need to continue if user's language is default if($language->isDefault()) return; $page = $event->arguments[0]; // not using, but here if you need it $field = $event->arguments[1]; // not using, but here if you need it $value = $event->arguments[2]; $rootUrl = rtrim(wire('config')->urls->root, '/'); // find links if(!preg_match_all('{href=[\'"]([-_./a-z0-9]+)}[\'"]', $value, $matches)) return; foreach($matches[1] as $key => $url) { // slice off subdirectory if site is running from one, so we have a clean URL from PW-install root if($rootUrl && strpos($url, $rootUrl) === 0) $url = substr($url, strlen($rootUrl)); // see if this is a link to a PW-managed page in the site $linkPage = wire('pages')->get($url); if(!$linkPage->id) continue; // now that you have the $linkPage and know the $language you should be able to // get the language URL right? I don't know how you do it, so I'll pretend: $langUrl = $this->getLanguageUrl($linkPage, $language); // replace the default language URL with the language URL $value = str_replace($matches[0][$key], "href='$langUrl'", $value); } $event->return = $value; }
  24. That's a good idea! And it's already there. But you have to be logged in to see it. See the sidebar, it says "create new blog post". You always have great suggestions, but sometimes it takes me awhile to get it. After sleeping on it and thinking more on the intended audience here and want it to be as broad as possible. So while I want this to be something that people don't have to touch any code, I also don't want to introduce any unnecessary barriers for people that do. Given what you've suggested, I'm thinking I will tear into it and make it less nice on the code side, but simpler for someone to figure out without having to invest much time in it. Here's the strategy: $markup, $output and $blog will get moved into 1 API variable just called $blog. That API variable will be moved to a module and won't be something that people ever have to look at the code for. The functions in it are: findPosts($selector) getPost($selector) findComments($selector) findRecentComments($limit) setOutput('content|sidebar|whatever', $value) renderPosts($posts) renderComments($comments) renderCategories($categories) renderSubnav($items) renderArchives($year) renderAuthor($author) renderWidgets($widgets) render() // main Rather than having the Markup class, all those render functions map to PHP "views": renderPosts() uses view file: /site/templates/blog/posts.php renderComments() uses view file: /site/templates/blog/comments.php ...and so on: subnav.php archives.php author.php widgets.php main.php Those view files are basically like WordPress templates. Though with no classes, functions or logic. Just markup, loops and variables. The render functions figure out the logic and then just hand the views data that's ready to be output. Not quite as flexible as before (though still flexible), but there's nothing to figure out, so I like that. The template files in /site/templates/ will remain largely the same, other than that they'll be calling on $blog rather than $markup and $output like they are now. What I think this leaves us with is a minor compromise, though one that has a much lower development barrier to entry. People can get in there and adjust the markup output without having to know anything about the system. So I think it's a good compromise. Structurally I think it may be better too because it's much easier to see the scope of a theme: the entire /templates/ dir (and other dirs in it) is it. This setup is kind of similar to the approach some of us use in having common render functions as modules. Like having a PageArray::renderVillas() that is used by multiple template files. The main difference here is that the render() functions are taking care of any needed logic and then letting really simple "view" files handle generating the actual output. So now the "theme" has good separation and hopefully encourages people to create new themes. It's not an approach I'd use on one of my projects, but it should be a perfect approach for this blog and encouraging people to customize it.
  25. $pages->get() will always return a Page object, so rather than doing this: if($type_of_oper) { you should do this: if($type_of_oper->id) { When a $pages->get() doesn't match anything, it returns a NullPage. The easiest way to check for a NullPage is by seeing if it has an id, like above. Though you could also do this if you preferred: $p = $pages->get($selector); if($p instanceof NullPage) { // no page found } else { // page found }
×
×
  • Create New...