Jump to content

marco

Members
  • Posts

    22
  • Joined

  • Last visited

Everything posted by marco

  1. Hi Jonathan, I added your little patch, and it helped preventing the recursion problems. The site content has been indexed.
  2. Nesting level of 1000 didn't help. Deactivating the xdebug extension led to an memory exhaustion error (as expected). This is an endless recursion problem (I think) and therefore cannot be solved by any type of php confoiguration. A possible solution could be to limit indexing the actual text fields, especially ignoring fields that reference other pages to prevent circular references.
  3. Yes, I'm running xdebug (and already increased the nesting level to 400). But as the error message shows, there is an endless loop in function calls. So increasing the nesting level won't help.
  4. Hi Jonathan, I just installed the module and tried to perform the initial indexing. But I got the following nesting-level-exceeded error (using win/php5.4.6) ( ! ) Fatal error: Maximum function nesting level of '400' reached, aborting! in ...\wire\core\Template.php on line 206 Call Stack # Time Memory Function Location 1 0.0013 164624 {main}( ) ..\index.php:0 2 0.2451 12483568 ProcessPageView->execute( ) ..\index.php:195 3 0.2451 12483680 Wire->__call( ) ..\index.php:195 4 0.2451 12483680 Wire->runHooks( ) ..\Wire.php:317 5 0.2452 12485280 call_user_func_array ( ) ..\Wire.php:359 6 0.2452 12485376 ProcessPageView->___execute( ) ..\Wire.php:359 7 0.2555 12579304 Page->render( ) ..\ProcessPageView.module:167 8 0.2555 12579416 Wire->__call( ) ..\ProcessPageView.module:167 9 0.2555 12579416 Wire->runHooks( ) ..\Wire.php:317 10 0.3390 13117808 ElasticSearch->checkForRebuildSearchData( ) ..\Wire.php:381 11 0.4550 13572320 ElasticSearch->updatePageContentInElasticSearch( ) ..\ElasticSearch.module:127 12 0.4574 13586960 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:209 13 0.4684 13640000 ElasticSearch->getRepeaterTypeAsContent( ) ..\ElasticSearch.module:149 14 0.4684 13640880 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:198 15 0.4759 13942032 ElasticSearch->getPageTypeAsContent( ) ..\ElasticSearch.module:147 16 0.4759 13942048 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:190 17 0.4760 13943400 ElasticSearch->getRepeaterTypeAsContent( ) ..\ElasticSearch.module:149 18 0.4760 13944240 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:198 19 0.4761 13945496 ElasticSearch->getPageTypeAsContent( ) ..\ElasticSearch.module:147 20 0.4761 13945496 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:190 21 0.4762 13946848 ElasticSearch->getRepeaterTypeAsContent( ) ..\ElasticSearch.module:149 22 0.4762 13947688 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:198 23 0.4764 13948944 ElasticSearch->getPageTypeAsContent( ) ..\ElasticSearch.module:147 24 0.4764 13948944 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:190 25 0.4764 13950296 ElasticSearch->getRepeaterTypeAsContent( ) ..\ElasticSearch.module:149 26 0.4764 13951136 ElasticSearch->getAllContentForPage( ) ..\ElasticSearch.module:198 27 0.4766 13952400 ElasticSearch->getPageTypeAsContent( ) ..\ElasticSearch.module:147 .... I think there must be a problem with recursions of page and/or repeater fields. Did you experience something like this? Is there a patch for the module that prevents this recursion type effects? regards, Marco
  5. The module is submitted to the module store at modules.processwire.com and waiting fpor approval. As for the $this->db vs. $this->database issue: I'll will update this accordingly to meet the needs of future releases as soon as it becomes necessary.
  6. Hi Folks, I just added a small module that keeps track of search keywords encoded in http referrers from common search engines leading to your site. See the README for a full documentation of features. Please let me now, if you have found any issues, feature requests or opinions by leaving your comments here in the forum or on github. Regards from Hanover, Germany, Marco
  7. Just updated the Twig library that is shipped with the module to the current release v1.15.0.
  8. Hi, I just released the new minor version 1.0.4 of the TemplateTwigReplace module. The module now lets you access the Twig_Environment instance used for rendereing pages and chunks via a public getter. So now you may customize the twig environment (e.g. by adding custom filters) to better meet your needs. Please take a look at the modified readme. Regards, Marco
  9. Thanks for your replies. After looking at the other topics mentioned, I think it might be best to wait for the "official" solution in PW 2.5. For the time being I will spend some additional time thinking about the problems I faced so far. I'll let you know if I've stumble about a solution or at least some good ideas.
  10. Hi folks! Despite of ProcessWire being one hell of a cms, we and our clients' editors stumbled upon one issue that is at least annoying and sometimes a major drawback that could lead to customers favoring another software for their projects: In ProcessWire you cannot update an already public pages without simultanously modifing the page's public appearance. In short, we cannot save drafts, use editing copies ore any similar form of manipluating content that should not be published immediatly. This is quite a common use case if you like to - preview your changes before publishing (already addressed by the preview module]) - edit content in teams. - want to schedule publishing of updated content for a future date. - have to apply some kind of approval chain before publishing updates. - just want to quit working for today and continue tomorrow. Personally I think, this should possible a feature request for a future core release instead of a plugin module discussion. But plugin modules are all we have at hand for the time being. ### Reqirements ### So let's start collecting a list of requirements: - New logic is only needed when editing already public pages. No need to mess with the process of editing non-public pages. - Opening a public page for editing: - Instead of presenting the current public state of the page some kind of draft state has to be used to initialize the editing form. - A draft state euqlas the page's state at the time of the last publishing - potentially modifed by preceeding save-as-draft actions of an editor. - The draft state covers the sum of the field values of the page (existing of database content, files of image fields and maybe other forms of serialized data in case of more exotic custom field types being used). - Additionally pages consist of a set of "direct" properties, such as templates_id, parent_id, status, and sort being the most important. Whether this kind of data should or must be part of a draft state is still to be discussed. - Instead of one rather two different saving options must be offered to the editor: save changes and publish changes. - Save changes - When saving changes the public state of a page has to left untouched. - The contents of the editing form must be serialized in a different way updating or replacing any existing draft state or creating a new one if necessary. - Publish changes - This option equals the normal publishing action on public pages as it is implemented right now (due to the editing form being initialized with the current draft state instead of the page's public state). - Delete pages - When deleting a page (entirely) any existing draft state has to be discarded as well. - Preview pages - We need to provide a new preview option (in contrast to the view option) that allows rendering the page's draft state instead of the public page. - This function should be accessible from the editing view as well as from the page tree. There might and probably will be more requirements, but I think this list covers the most common aspects of a save-as-draft feature. As I'm writing this post, I already invested some time trying to implement a plugin module. Unsurprisingly I stumbled upon a bunch of obstacles leading to a halt and seeking help and opinions from the comunity. I'll try to describe the general strategies I came up with for implementing the draft state feature: ### Cloning the page ### My first attempt was to implement a cloning mechanism that duplcates a public page storing it in a hidden folder. The I tried hooking into ProcessPageEdit::execute() trying to replace the originl page object handdles by the module with my draft copy. This approach came to a halt due to the following problems: - The page object within ProcessPageEdit is stored within a protected property ($this->page) and referenced by all the methods of the module. Their is no direct way to manipualte that via a hook. I came up with some kind of dirty hack to circumvent that but this was far from a satisfying solution. - Some parts of the editing form still had to show details of the original page (e.g. the breadcrumps, the children, the state), so the page object used to initialize the editing form had to be some kind of mix of the public and the draft state of the page. - Most of this mixing state issues could be solved for the initializing. But when it comes to saving the draft state (not publishing changes) the need to divide the editing form's content in draft data and public data could not be solved (at least by me). ### Cloning field values ### The second approach was to not clone the entire page but all the page's fields to represent the draft state. This would solve the issues with special treatments for form values for status and template and therefor should be more elegant and "light-weight" in our efforts to mess with ProcessWire's default behaviour as less as possible. I tried hooking into Fieldtype::savePageField() and FieldtypeMulti::savePageField() providing special logic for storing field values in case of a public page being saved as draft. Additional the former mentioned hooking into ProcessPageEdit::execute() used to unserialize this draft field values and overwrite the page's public field contents. The main problem I encountered was that there are more than this two types of FieldtypeXYC::savePageField() implementations (Repeater, I'm looking at you!). Every custom Fieldtype module can and often will come up with its own implementation of serializing values which would have to all be hooked into seperatly (correct my if I'm wrong on this one) and handled accordingly rendering a generic Save-as-draft module useless. ### Cloning the form state ### So I tried a more direct approach, ignoring the existance of pages and fields completly, just looking at the editing form alone. A page's draft state can be represented by the pure form state (meaning the list of form elements and their values). So save-as-draft action could possibly be implemented by intercepting the svaing process of the ProcessPageEdit module, grabbing the form state and serializing it instead of the normal routine. Unfortunatly ProcessPageEdit::processSave() is a protected and therefor unhookable method. But even if that wwasn't the case, you still had to face a mix of the same problems that we encountered in the first two approaches (separating draft form values from public state values and the need of implementing different ways of serializing the form state for a multitude and mostly unknown list of different field types. Additionally you would have to duplicate a lot of code e.g. form validation and handling file uploads that has been covered deep in the guts of the ProcessPageEdit module. ### Starting the discussion ### So, this was a looong intro. And I already thank you if you're still with me. If you have any thoughts regarding - the core feature vs. module question - the list of requirements I came up with so far - my efforts in conecpting and implementing a plugin module - or the need of this kind feature in general drop me line (or two). Regards, Marco
  11. Hi folks, I recently released the module Template Twig Replace that enables templating using the Twig engine instead of the default php/html templates. The module hooks into PageRender::___renderPage, replacing the original method and setting the Twig rendering results to the event's return property. I've taken a good amount of information from this post to achieve the results. Now I've discovered that pages will not be cached if the module is active. Some digging into the core (/wire/modules/PageRender.module) showed, that the method, I'm hooking not only renders a page but handles page caching (and some form of access control) as well. As a quick fix I duplicated the code handling cache files in my module to ensure pages a properly cached as usual. The fix is already commited to github and should be available in the module directory soon. This is would my module currently looks like: public function init() { // ... some more stuff .. // replace default page rendering by hooked method $this->addHookBefore('PageRender::renderPage', $this, 'renderPageWithTwig'); } /** * Hook callback for PageRender::renderPage * * Replaces default page rendering entirely. * * @param HookEvent $event The hook event * @throws WirePermissionException Page is not currently viewable. */ public function renderPageWithTwig(HookEvent $event) { $parentEvent = $event->arguments(0); // grab event provided to PageRender::renderPage // don't mess with admin templates $page = $parentEvent->object; if ($page->template == 'admin') return; // double check page's status // taken from PageRender::__render() if ($page->status >= Page::statusUnpublished && !$page->viewable()) { throw new WirePermissionException('Page \'' . $page->url . '\' is not currently viewable.'); } // forced replacing of default page rendering behaviour $event->replace = true; // look for cached data // taken from PageRender::__render() $options = count($parentEvent->arguments) ? $parentEvent->arguments[0] : array(); $defaultOptions = array( 'forceBuildCache' => false, ); $options = array_merge($defaultOptions, $options); $cacheAllowed = wire('modules')->get('PageRender')->isCacheAllowed($page); $cacheFile = null; if ($cacheAllowed) { $cacheFile = wire('modules')->get('PageRender')->getCacheFile($page); if(!$options['forceBuildCache'] && ($data = $cacheFile->get()) !== false) { $parentEvent->return = $data; return; } } // allow page fields to be accessed directly in Twig // e.g. {{ page.myfield }} instead of {{ page.get('myfield') }} Page::$issetHas = true; // render template $twigVars = $this->collectVariables($page->output); $output = $this->getTwig()->render($page->template->name . '.' . wire('config')->templateExtension, $twigVars); // cache output if possible // taken from PageRender::__render() if (!empty($output) && $cacheAllowed && !is_null($cacheFile)) $cacheFile->save($output); // manually set return of original event $parentEvent->return = $output; } But I think, the best option would be finding a hook the only renders a page's content and replacing this method. Is there a better hook to use that leaves handling page caching and maybe other pre- or post-processing alone and does template rendering only? Regards, Marco
  12. Hi Ryan, I just pushed a new version of my Template Twig Replace module to github and tried to edit the module's version number in the directory setting it to v1.03. But my changes do not asppear in the directory. And I think therefore the Module Manager doesn't show any update hints. Is there a delay between submitting the module edit form and the updating of the module directory? Regards, Marco
  13. Hi folks, as announced yesterday, I just published my new Template Twig Replace module on github. The module lets you write Twig templates directly, making calls like $page->twig('my_template.twig') in an otherwise empty php template unnecessary. It also seamlessly integrates with my other module Template Data Providers that can be found here and here. Be sure to consult the README.md for further information. Please leave your comments, opinions, and suggestions here in this forum or at github and I'll try to answer as quick as possible. Honorable mentions go to porl and his Template Twig module for inspiring this little piece of code. Regards, Marco
  14. Please answer to this post instead.
  15. Hi all, I just released my first module on github called Template Data Providers. This module lets you create simple data provider classes for templates and chunks (a.k.a. partials, blocks, includes, ...) to gather and prepare data for templates and/or handling form data and other actions outside of the templates ("separation of concerns"). But even if you've installed the module the usage of the new functionality is merely optional. You may define your simple templates and chunks as usuals, adding custom classes (PageDataProvider for pages/templates, ChunkDataProvider for chunks) for more complex data handling on demand. I provided detailed instructions in the README.md and encourage you to read it for further information. Just some sample code here: Defining a data provider for a home template: class HomePage extends \nw\DataProviders\PageDataProvider { public function populate() { $this->foo = 'bar'; // definevariable $foo to use within the page's template $this->page->foo = 'baz'; // provides page member $page->foo to use within the page's template } } Calling a chunk from within a template: $page->renderChunk('path/to/primary-navigation.php'); // relative to site/templates/ Calling a chunk providing contextual data: $news = $pages->get('template=news'); foreach ($news as $newsItem) { $page->renderChunk('path/to/news-item.php', $newsItem); // additional arguments provided will be avaiable within the chunk in a closed scope } Defining an example chunk data provider: class ExampleChunk extends \nw\DataProviders\ChunkDataProvider { public function setContext(array $context = array()) { // store first context argument in $this->foo $this->foo = isset($context[0]) ? $context[0] : null; // store second context argument in $this->bar if instance of \Page $this->bar = null; if (isset($context[1]) && $context[1] instanceof \Page) { $this->bar = $context[1]; } } public function populate() { $this->foo = 'bar'; // provides variable $foo to use within the chunk } } Please leave your questions, remarks, error reports here in the forum or at github and I'll try to answer as soon as possible. This module is a preparation for another module coming soon. This will be an alternative Twig template engine module that will interact with Template Data Providers or could be used as stonde-alone module. Regards from Hanover/Germany, Marco
  16. SOLVED !!! My class (AbstractController) that provides the hook method (___render()) is located in a namespace (nw\Controllers\AbstractController). So hooking into this method requires a fully qualified class name: $this->addHookBefore('nw\Controllers\AbstractController::render', $this, 'doStuff');
  17. This has nothing to do with my AbstractController being abstract or not. The problem is, that the base class provides a hook and is designed to be subclassed. But users can't hook into the method (in this case ___render()) of the base class but would have to hook into every ___render() method of all subclasses which makes this form of abstraction unusable in a ProcessWire context,.
  18. Hi, I'm currently working on a module that provides controller (as from mvc patterns) functionality for gathering data for page rendering (more to come soon). And now I'm facing a specific problem: I created an abstract controller class (lets say AbstractController) that extends WireData. This controller class is ment to be sub classed in ProcessWire projects by the project developers for each template that needs additional data to display. Now this abstract controller should get a hookable render() method. So I defined public function ___render(). Now if I try to hook in from another plugin via $this->addHookBefore('AbstractController::render', $this, 'doStuff'); nothing happends. Lets assume I have a HomeController extending AbstractController providin data for the home template. Now I can hook in via $this->addHookBefore('HomeController::render', $this, 'doStuff'); because HomeController inheritats the ___render() methods from its parent. The problem is, I don't want to hook into every concrete controller but into their common parent, the AbstractController, instead. Is there any solution to this problem? Regards, Marco
  19. I had to commend out a line in the Indexer.module file (v0.5.1, line 246, getKeywords()) that strips numbers from indexed text. I had to do this, because my site contains product names using numbers (e.g. "serviceFLAT360") that weren't be found. Perhaps you could introduce a config option for the module to enable/disable number stripping.
  20. Sorry, if repost, but I couldn't find a suitable answer to my question: I'd like to insert a download link in a richtext field using the ckeditor. The control lets me select contents of image fields throughout my page, but not the contents of file fields (which I need to select a zip file as download target). So what is the designated way to specify download targets other than image files? .......................... SOLVED: Was my fault completely. Seems that the file I'd liked to target wasn't uploaded due to an excluded file extension (.zip). Sorry again for spaming here.
×
×
  • Create New...