Jump to content

gRegor

Members
  • Posts

    111
  • Joined

  • Last visited

  • Days Won

    2

Everything posted by gRegor

  1. I've set up a Process module that displays various views in the admin area. The contents of these views are built in the ___execute* functions, but I was wondering if anyone has any recommended practices for separating out the view "templates" into separate files. I suppose I could just put template files in the module's directory and require() them from the function calls, but wasn't sure if there's a better / more ProcessWire-y way to do it.
  2. And then I found FieldtypeSecureFile. Figures. https://processwire.com/talk/topic/10671-fieldtypesecurefile/
  3. I have a solution that 90% works, which is good enough for my needs. I have the complicated situation where there's an Images field, which needs to remain public, and a Documents field which needs to be protected in some situations. In my setup, I have a checkbox field is_member_page which is used to require authentication to view the page, so I've also used that in my hooks: # For files that should be protected, set the path to the .page-id files directory. Should auto-create the directory. $this->addHookAfter('PagefilesManager::path', function($event) { $page = $event->object->page; if ( $page->is_member_page ) { $event->return = dirname($event->return) . '/.' . $page->id . '/'; } }); I was using this next hook for a while, so the URL in the admin area pointed automatically to the download pass-through page. What I ran into is that this broke the preview in the Images field, though, so I opted against it. This means when I insert links to the files, I have to manually craft them. It's a minor inconvenience for being able to still preview and easily insert the images, though. # Optional; if you want to change the URL to automatically point to the download pass-through page. # Be sure to replace/set $YOUR_PAGE_ID as appropriate. $this->addHookAfter('PagefilesManager::url', function($event) { $page = $event->object->page; if ( $page->is_member_page ) { $event->return = wire('pages')->get($YOUR_PAGE_ID)->url . $event->object->page . '/' . $event->object->name; } }); This is where it gets a bit tricky, and violates DRY a bit. The above hooks affect the path and url for all file fields. I tried and tried, but I could not conditionally change them for only the Documents field while leaving the Images field. Instead, what I've done is checked if the inputfield is a FIle or an Image. If it's an image, I make a copy of it in the public folder, so it can be previewed in the backend (and used on the page ). $this->addHook('InputfieldFile::fileAdded', function($event) { if ( get_class($event->object) == 'InputfieldFile' ) { $file = $event->arguments(0); $path = $file->filename(); $page = $file->page; # if: member only page if ( $page->is_member_page ) { $secure_path = dirname(dirname($path)) . '/.' . $page->id . '/'; if ( !$file->copyToPath($secure_path) ) { $this->log->save('messages', "Error copying secure file to: {$secure_path}"); } } # end if } else if ( get_class($event->object) == 'InputfieldImage' ) { $file = $event->arguments(0); $path = $file->filename(); $page = $file->page; $public_dir = dirname(dirname($path)) . '/' . $page->id . '/'; # if: file does not exist in public dir yet; copy it if ( !file_exists($public_dir . $file->name) ) { if ( !$file->copyToPath($public_dir) ) { $this->log->save('messages', "Error copying file to: {$public_dir}"); } } # end if } }); Finally, to clean up my DRY mess, I make sure when an image is deleted from the protected directory, it's also deleted from the public directory. $this->addHook('InputfieldFile::processInputDeleteFile', function($event) { $file = $event->arguments(0); $path = $file->filename(); $page = $file->page; $public_path = dirname(dirname($path)) . '/' . $page->id . '/' . $file->name; if ( file_exists($public_path) ) { unlink($public_path); } }); My download pass-through page template is similar to the ones mentioned earlier in this thread, though I check the file extension and if it's a PDF I deliver it with MIME type application/pdf and not with Content-Disposition: attachment -- that way the PDF can be previewed in modern browsers, depending on the user's settings. (I can share this template too, if anyone is interested). Any feedback is welcome!
  4. Thanks for that PageArray trick. That works great and I think I can keep 2.5+ support. And thanks for the Github info!
  5. I'm working on adding a Webmention Manager to my module, using Comment Manager as the basis. I'm still on PW 2.5.3 and trying to build the module to work on 2.5+ (the only reason I haven't upgraded yet). I realized that the PaginatedArray class isn't in the 2.5.3 code, so was going to add backcompat code to the module. I was wondering when the PaginatedArray class was added to core, but having a hard time determining that. Is there an easy way to find out, short of searching through each of the version tags on Github? Perhaps the doc parameter @since could be added to the doc comments, so I could tell by looking at the master branch? While on the topic, is the best way to include such backcompat to check for the existence of the class and then include it if it doesn't exist? Edit: Hmm, so I'm realizing that the updates adding PaginatedArray and WirePaginatable go deeper than I expected. For example, I cannot use the MarkupPagerNav because it expects a PageArray input, not my WebmentionArray (which implements WirePaginatable). Perhaps it's best to just make my module 2.6+, unless someone has some good advice for backwards compatibility.
  6. Thanks for the kind words, Johannes. Yes, making the plugin more flexible about the fields it looks for URLs in is something I've been thinking about. I chose "body" since it seems the most common field people will have in their templates, but even that is not guaranteed. I think I will add a module configuration that will accept a comma-separated list of fields to check for URLs. If the template has one of those fields, it will parse for URLs and send webmentions to them. This is something I already need for my site. For example, my notes have a separate field for the in-reply-to URL, so I currently cannot webmention those URLs automatically. This module will work with your Brid.gy backfeed, by the way. P.S. I made a reply to this note and sent a webmention.
  7. Yes, if the WordPress site supports webmentions. If the site doesn't support webmentions and does support pingback, this module will fallback to sending a pingback. There are WordPress plugins to add webmention support,. See http://indiewebcamp.com/WordPress for more info. As I understand it, there's actually two plugins to get the full features: Webmention and Semantic Linkbacks. The latter gives you more user-friendly text for linkbacks (of all types). There's a pretty active group of WordPress users in the indiewebcamp community and I know they'd love to help anyone get set up with these plugins. Feel free to stop by the IRC for any help: http://indiewebcamp.com/IRC
  8. Thanks, teppo! Yeah, I was looking over the code after I posted and realized I should be using prepared statements. D'oh! I'll make that fix quickly Yeah, the WireHttp shim gives you an indication how long I've been working on this, heh. I decided to leave it in for now so that the module could be 2.5-compatible; I think my WireHttp PR didn't make it in until 2.6 (not sure which version, exactly). Perhaps I could perform a version check in the code and if it's before X, use the shim, otherwise use the core version.
  9. An example of some cool things this enables: If you add some simple microformats to your HTML, the recipient of a webmention can parse out the content of your post and display it as a comment on their own site; federated commenting! For example, I posted this silly physics pun on my site, sent a webmention to the URL it was in-reply-to, and the recipient's website parsed the microformats to display my comment.
  10. Updated 2018-05-06: Version 2.0.0 released Updated 2017-03-27: Version 1.1.3 released Updated 2016-04-11: Version 1.1.2 released Updated 2016-02-26: Officially in the module directory! http://modules.processwire.com/modules/webmention/ Updated 2016-02-25: Version 1.1.0 is now released. It's been submitted to the module directory so should appear there soon. In the meantime, it's available on GitHub: https://github.com/gRegorLove/ProcessWire-Webmention. Please refer to the updated README there and let me know if you have any questions! ------------ Original post: This is now out of date. I recommend reading the official README. I've been working on this one for a while. It's not 100%, but it is to the point I'm using it on my own site, so it's time for me to release it in beta. Once I finish up some of the features described below, I will submit it to the modules directory as a stable plugin. For now, you can install from Github. It works on PW2.5. I haven't tested on PW2.6, but it should work there. Feedback and questions are welcome. I'm in the IRC channel #processwire as well as #indiewebcamp if you have any questions about this module, webmention, or microformats. Thanks to Ryan for the Comments Fieldtype which helped me a lot in the handling of webmentions in the admin area. ProcessWire Webmention Module Webmention is a simple way to automatically notify any URL when you link to it on your site. From the receiver's perspective, it is a way to request notification when other sites link to it. Version 1.0.0 is a stable beta that covers webmention sending, receiving, parsing, and display. An easy admin interface for received webmentions is under development, as well as support for the Webmention Vouch extension. Features * Webmention endpoint discovery * Automatically send webmentions asynchronously * Automatically receive webmentions * Process webmentions to extract microformats Requirements * php-mf2 and php-mf2-cleaner libraries; bundled with this package and may optionally be updated using Composer. * This module hooks into the LazyCron module. Installation Github: https://github.com/gRegorLove/ProcessWire-Webmention Installing the core module named "Webmention" will automatically install the Fieldtype and Inputfield modules included in this package. This module will attempt to add a template and page named "Webmention Endpoint" if the template does not exist already. The default location of this endpoint is http://example.com/webmention-endpoint After installing the module, create a new field of type "Webmentions" and add it to the template(s) you want to be able to support webmentions. Sending Webmentions When creating or editing a page that has the Webmentions field, a checkbox "Send Webmentions" will appear at the bottom. Check this box and any URLs linked in the page body will be queued up for sending webmentions. Note: you should only check the "Send Webmentions" box if the page status is "published." Receiving Webmentions This module enables receiving webmentions on any pages that have have "Webmentions" field, by adding the webmention endpoint as an HTTP Link header. If you would like to specify a custom webmention endpoint URL, you can do so in the admin area, Modules > Webmention. Processing Webmentions (beta) Currently no webmentions are automatically processed. You will need to browse to the page in the backend, click "Edit," and scroll to the Webmentions field. There is a dropdown for "Visibility" and "Action" beside each webmention. Select "Process" to parse the webmention for microformats. A better interface for viewing/processing all received webmentions in one place is under development. Displaying Webmentions (beta) Within your template file, you can use `$page->Webmentions->render()` [where "Webmentions" is the name you used creating the field] to display a list of approved webmentions. As with the Comments Fieldtype, you can also generate your own output. The display functionality is also under development. Logs This module writes two logs: webmentions-sent and webmentions-received. Vouch The Vouch anti-spam extension is still under development. IndieWeb The IndieWeb movement is about owning your data. It encourages you to create and publish on your own site and optionally syndicate to third-party sites. Webmention is one of the core building blocks of this movement. Learn more and get involved by visiting http://indiewebcamp.com. Further Reading * http://indiewebcamp.com/webmention * http://indiewebcamp.com/comments-presentation * http://indiewebcamp.com/reply
  11. +1 for allowing original capitalization. To avoid name collisions on Windows, the unique filename comparison could still use the lowercase filename, but append n to the original filename instead of the lowercase filename. processwire.gif, ProcessWire.gif, and PROCESSWIRE.GIF would become: processwire.gif, ProcessWire-1.gif, and PROCESSWIRE-2.GIF Alternately, is there a way in PHP to detect the file system's case-sensitivity?
  12. Per discussion with @renobird in IRC, I've decided to add child pages that also use ProcessDocumentation and then grandchild pages that use template: documentation. Then the ___execute() method will display the page contents and/or a list of links to the sub-pages as appropriate.
  13. I've set up a basic module, ProcessDocumentation, that is intended to add a tree of documentation pages under the Admin page. The module doesn't actually use templates to display anything. The ___execute method displays a list of links to the documentation pages (child pages). Clicking on one of those, the ___executeView method uses the URL segment to load the appropriate page contents and display it. This works OK when using the default theme. There is no expanded sub-menu (e.g. hovering over Setup > Templates displaying the list of templates), but the top-level "Documentation" page is clickable which displays the list of pages. In Reno, though, those links are in the sidebar and the top-level links are click-to-expand. I'm having difficulty displaying the child documentation pages in Reno when clicking to expand, without using a template file. It looks like in AdminThemeRenoHelpers::renderSideNavItem() method it's loading child pages that are viewable. Since the documentation pages don't use a template, they're not getting populated. I've toyed around with the 'nav' key in the getModuleInfo() but that doesn't seem to work. I also tried out renderListJSON() and ___executeNavJSON() which I saw in some other modules, but I'm pretty sure those aren't used in this context, but in the search methods. I could add a template file, of course, but I don't want to render an entirely different layout. I just want to display the regular admin interface with the documentation page body in the main content area. Any suggestions?
  14. I added a FieldtypePage to the basic-page template to confirm what you're saying and it shows up. And now I can't duplicate the empty Webmentions field returning a null value, so I guess something got fixed when adding a field? No idea. :] I will have to try a fresh install of the module to ensure it works out of the box. For FieldtypeWebmentions I used the Comments module as a guide since they're very similar. I couldn't find anything specific in the comment module that would determine what's returned for $page->fields. I had tried $page->templates->fields before with the same result, though my understanding is $page->fields is just a shortcut reference to it.
  15. This is the method I have gone with so far and after lots of testing seems to be working smoothly, so I will consider that to be my answer unless someone else chimes in. :]
  16. As part of the webmention module I am working on, I want to detect if the page being viewed has the "Webmentions" field and if so, add a Link: header. I have hooked before PageRender::renderPage to add the header and that works OK. I am having trouble checking for the Webmentions Fieldtype, though. FieldtypeWebmentions extends FieldtypeMulti and is empty on new pages. My code below does not work because the $field->type is returning NULL when the Webmentions field is empty. When the Webmentions field is not null, then it returns the Fieldtype as expected. How can I reliably check if a page's template has a specific Fieldtype, whether the field is empty or not? Am I missing something in the Fieldtype or Inputfield classes for the module? Thanks for any help! private function findFieldtypeWebmentions(Page $page) { # loop: each field for this page foreach ( $page->fields as $field ) { if ( $field->type instanceof FieldtypeWebmentions ) { $this->webmention_field = $field; return TRUE; } } # end loop return FALSE; } # end method findFieldtypeWebmentions()
  17. I am working on a plugin to implement webmentions in ProcessWire. Webmention is a modern update to Pingback - a simple way to notify a URL that you linked to it, without the XMLRPC overhead. I'm working on a module and an accompanying Fieldtype to store the webmention data. I'm using the Comments module as starting point and mostly understanding it. The thing I'm not sure about, though, is the best way to have the module automatically save the values for webmentions when they are sent (or received). Similar to the Comments module, I have a WebmentionArray class and WebmentionItem class. In the module, I'm hooking Pages::saved to send webmentions and log them. Should I do something like: // inside the Pages::saved hook $page = $event->arguments('page'); $webmention = new WebmentionItem(); // set webmention fields (these keys exist in the Fieldtype) $webmention->set('source_url', 'http://example.com/source'); $webmention->set('target_url', 'http://example.com/target'); // add webmention to field array $page->webmentions->add($webmention); $page->save(); Do I need to deal with a WebmentionArray class at all in this scenario, or does $page->webmentions->add() automatically handle adding it to the array?
  18. Thanks marcus and Martijn. I found the saveModuleConfigData() method last night and ended up using: $this->modules->saveModuleConfigData($this, self::getDefaultData()); Works like a charm!
  19. I think I figured this out. I thought getModuleConfigInputFields() was somehow being passed the values set in __construct(), but it's not. This method is just determining what fields will be shown on the module settings page; values are not stored in the database until the first time you click 'submit'. If a value exists in the database, then $this->foo will contain that value. Otherwise it will default to what's set in the __construct(). I was getting caught up because I thought the default values had to be in the database before the module would let me use them. An important thing to do, to avoid accidental blank values in the database, is ensure getModuleConfigInputFields() displays the default values if none are in the database yet. I took some code from this post to achieve that, merging the default values with the supplied $data array. In array_merge(), values in the latter arrays always take precedence. $data = array_merge(self::getDefaultData(), $data); I am still curious how I might store the default options in the database during install, though. Particularly if I wanted to go the second route I mentioned in the other thread. In that instance, during installation the module would loop through until a unique field name was found, and would need to store that name in the module options.
  20. First, I am running PW 2.4.12, so I realize this might be a beta bug that is fixable by me upgrading, but I'm following examples that have been around for a while, so I figured I would ask. I am following the wiki's example for making a configurable module and it creates the fields properly, but is not storing the default values on install. In the __construct() method I have tried both variants: # variant 1 $this->foo = 'value'; # variant 2 $this->set('foo', 'value'); And then my getModuleConfigInputFields(array $data) method has: $inputfields = new InputfieldWrapper(); $field = wire('modules')->get('InputfieldText'); $field->name = 'foo'; $field->label = 'Label for foo'; if ( isset($data['foo']) ) { $field->value = $data['foo']; } $inputfields->add($field); return $inputfields; After install, the module shows the field, but its value is blank. I've confirmed the 'data' field in the modules table is blank, too. At this point, I can enter a value, click submit, and the 'data' field is updated and reflects in the form. Is there an additional method call needed in my __install() to trigger storing these default values?
  21. I would check if any pages are still using the template and only remove it if it was zero. I might make it a config option to have the module remove its pages on uninstall, though.
  22. I am working on a module that will require a template and certain set of fields. I was wondering what the best practices are to achieve this. I have used soma's Images Manager module and I noticed it requires you to manually create some fields, templates, and pages. The current route I am considering is: Set the module up with ConfigurableModule and several options for the default field/template names. IF: the template and field names do not already exist:​Create the templates and fields, indicate install is completed successfully ​ELSE:Prompt the user to create the templates/fields manually and enter the names in the module's configuration. Alternately, I suppose the install method could take the base name for fields/templates and add an incremented number to the end until a unique name is found. This might be preferable since it would not require any manual configuration. Thoughts?
  23. An alternative that I just implemented: I set up field 'bootstrap_column' as a Repeater, with fields 'bootsrap_column_span' and 'body'. 'bootstrap_column_span' is an integer field with value range 1-12. Then I loop through the bootstrap_column field and keep track of the column spans, creating new rows as necessary: echo '<div class="row">'; $i = 0; foreach ( $page->bootstrap_column as $column ) { $i += $column->bootstrap_column_span; # if: over 12 columns; start a new row if ( $i > 12 ) { $i = $column->bootstrap_column_span; echo '</div> <!--/.row -->'; echo '<div class="row">'; } # end if echo sprintf('<div class="span%d"> %s </div>', $column->bootstrap_column_span, $column->body ); } # end loop echo '</div> <!--/.row -->'; It may not be the most efficient method and the repeater field doesn't reflect how it will look on the front end, but I think it will work for my needs so far. I actually didn't look into PageTable or setting up sub-pages for different sections of content. Edit: just realized I missed the conditions when the column span is exactly 12. I will need to add that.
  24. Thanks, horst and ryan. Wow, that's a really smooth process. I like the auto DB/htaccess updates. PW continually impresses me! Is there a way to tell what version the dev branch is at? I don't see tags for the minor version numbers. I guess it doesn't matter for the upgrade process; just curious.
×
×
  • Create New...