Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 10/25/2018 in all areas

  1. It depend on your needs, check : [...] const statusInit = 2; // system and modules are initializing const statusReady = 4; // system and $page are ready [...] E.g: in init.php, $page is not accessible (called too early) in ready.php, $page is accessible. Summarily said, new API variables are set (populated) before your prepended file to be consumed in your templates. If you want to access the $general variable as is from a template, you will have to set it in ready.php because here you can know the template/page context. Check those four examples.. Let's say we want to debug $general from our home.php template using Tracy with bd($general); #1 - Set new API var in init.php : (both call return null because we try to access the API var from a template, but still here the template context is unknown) $general is null $wire->general is null #2 - Set the new API var in ready.php : $general is populated $wire->general is populated #3 - Set the new API var in _init.php : $general is null $wire->general is populated #4 - Set the new API var in home.php : (same result as _init.php) $general is null $wire->general is populated Hopefully this will make thing clearer for you though an expert could explain deeper the thing.
    5 points
  2. Writing reusable markup generation functions Hello there, I've been working with ProcessWire for a while now, and I've been writing some helper functions to generate markup and reduce the amount of repetitive code in my templates. In this tutorial I want to explain how to write small, reusable functions and combine them to accomplish bigger tasks. Note that this is the follow-up to my last post, Building a reusable function to generate responsive images. In that tutorial, I demonstrated a pretty large function that generates multiple image variations for responsive images, as well as the corresponding markup. In this post, I'll split this function into multiple smaller functions that can be utilized for other purposes as well. This will be more beginner-orientated than the last one, I hope there's some interest in this anyway ? Note that for my purposes, I prefer to have those functions as static methods on a namespaced object, so the following code examples will be placed in a simple Html class. However, you can use those as normal functions just as well. class Html { // code goes here } Edit: Those functions use some syntax exclusive to PHP 7.1 and above, they won't work in PHP 7.0 and lower. Thanks for @Robin S for pointing that out. Seperation of concerns To split up the original function, we need to analyze all the individual tasks it performs: Generate several image variations in different sizes. Generate the corresponding srcset attribute markup according to the specification. Generate the sizes attribute markup based on the passed queries. Automatically include the description as the alt attribute. Generate the markup for all attributes (including the ones passed to the function). Generate the markup for the complete img tag. The first three of those tasks are very specifically concerned with generating responsive images. Generating the alt attribute is relevant to any img tag, not just responsive images. Finally, generating the attributes and HTML markup is relevant to all HTML markup that one wants to generate. Therefore, this is how a hierarchy between those functions could look like. Generate responsive image Generate image markup Generate any HTML tag markup Generate an HTML start tag Generate HTML attributes markup Generate an HTML end tag Those bullet points are the tasks I want to turn into individual functions, each accepting arguments as general as they can be, facilitating code reuse. I'll start writing those out from the ground up. Generating attributes markup HTML attributes are a list of property-value pairs, where the value is wrapped in quotation marks (") and assigned to the property with an equals-sign (=). Each pair is separated by a space. There are also standalone/empty attributes that don't have a value, for example: <input id="name" class="form-control" disabled> Since the input format consists of key-value pairs, it makes sense to use an associative array as the argument to the attributes functions. public static function attributes( array $attributes ): string { $attr_string = ''; foreach ($attributes as $attr => $val) { $attr_string .= ' ' . $attr . '="' . $val . '"'; } return $attr_string; } However, this still needs to support standalone attributes. Those attributes are also known as boolean attributes, since their presence indicates a true value, their absence the opposite. Since all other values in the markup are strings or integers, we can differentiate between those based on the type of the value in the associative array. If it's a boolean, we'll treat it as a standalone attribute and only include it if the value is also true. public static function attributes( array $attributes, bool $leading_space = false ): string { $attr_string = ''; foreach ($attributes as $attr => $val) { if (is_bool($val)) { if ($val) { $attr_string .= " $attr"; } } else { $attr_string .= ' ' . $attr . '="' . $val . '"'; } } if (!$leading_space) { $attr_string = ltrim($attr_string, ' '); } return $attr_string; } Of course, this means that if a value in the array is boolean false, this array item will be left out. This is by design, as it allows the caller to use expressions in the array declaration. For example: echo Html::attributes([ 'id' => 'name', 'class' => 'form-control', 'disabled' => $this->isDisabled() ]); This way, if isDisabled returns true, the disabled attribute will be included, and left out if it doesn't. Note that I also included a $leading_space argument for convenience. Generating start tags, end tags and complete HTML elements The start tag is identified by the element name and the attributes it contains. The end tag only needs a name. Those functions are trivial: public static function startTag( string $element, ?array $attributes = [] ): string { $attribute_string = self::attributes($attributes, true); return "<{$element}{$attribute_string}>"; } public static function endTag(string $element): string { return "</{$element}>"; } Of course, the startTag function builds on the existing function to generate the attributes. Note that a start tag is identical with a standalone tag (i.e. a void HTML element such as the img tag). At this point, it's also trivial to write a function that builds a complete element, including start and end tag as well as the enclosed content. public static function element( string $element, ?string $content = null, array $attributes = [], $self_closing = false ): string { if ($self_closing) { return self::startTag($element, $attributes); } else { return self::startTag($element, $attributes) . $content . self::endTag($element); } } Note that while this function does take several arguments, all except the first have reasonable default values, so usually the caller will only have to pass two or three of them. Some examples: echo Html::startTag('hr'); // <hr> echo Html::element('a', 'My website', ['href' => 'http://herebedragons.world']); // <a href="http://herebedragons.world">My website</a> Image tags Those functions make for a solid foundation to build any type of HTML element markup. Based on the type, the functions can accept more specific arguments to be easier to use. For example, the previous link example could be simplified by writing a link function that accepts a link text and an href value, since those are needed for any link: public static function link( string $url, ?string $text = null, array $attributes = [] ): string { // use url as text if no text was passed $text = $text ?? $url; $attributes['href'] = $url; return self::element('a', $text, $attributes); } Anyway, for our image markup function, we'll take a Pageimage object as an argument instead, since most images we will use in a ProcessWire template will come from the ProcessWire API. Since all ProcessWire image fields have a description field by default, we can use that description as the alt attribute, which is good practice for accessibility. public static function image(Pageimage $img, array $attributes = []): string { $attributes['src'] = $img->url(); // use image description as alt text, unless specified in $attributes if (empty($attributes['alt']) && !empty($img->description())) { $attributes['alt'] = $img->description(); } return self::selfClosingElement('img', $attributes); } Pretty simple. Note that the alt attribute can still be manually overridden by the caller by including it in the $attributes array. Responsive images Now, the responsive image function can be shortened by building on this function in turn. Optimally, the three distinct tasks this performs (see above) should be separated into their own functions as well, however in practice I haven't seen much need for this. Also, this post is plenty long already, so ... public static function imageResponsive( Pageimage $img, ?int $standard_width = 0, ?int $standard_height = 0, ?array $attributes = [], ?array $sizes_queries = [], array $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2] ): string { // use inherit dimensions of the passed image if standard width/height is empty if (empty($standard_width)) { $standard_width = $img->width(); } if (empty($standard_height)) { $standard_height = $img->height(); } $suffix = 'auto_srcset'; // if $attributes is null, default to an empty array $attributes = $attributes ?? []; // get original image for resizing $original_image = $img->getOriginal() ?? $img; // the default image for the src attribute $default_image = $original_image->size( $standard_width, $standard_height, ['upscaling' => false, 'suffix' => $suffix] ); // build the srcset attribute string, and generate the corresponding widths $srcset = []; foreach ($variant_factors as $factor) { // round up, srcset doesn't allow fractions $width = ceil($standard_width * $factor); $height = ceil($standard_height * $factor); // we won't upscale images if ($width <= $original_image->width() && $height <= $original_image->height()) { $current_image = $original_image->size($width, $height, ['upscaling' => false, 'suffix' => $suffix]); $srcset[] = $current_image->url() . " {$width}w"; } } $attributes['srcset'] = implode(', ', $srcset); // build the sizes attribute string if ($sizes_queries) { $attributes['sizes'] = implode(', ', $sizes_queries); } return self::image($default_image, $attributes); } See my last post for details. Since then, I made some changed to the function I outlined here (thanks to @horst for pointing out some pitfalls with my approach). Most notably: The generated images now include a prefix so they can be removed by a cleanup script more easily. The function now accepts a width and a height parameter so that the aspect ratio of the generated images is fixed (reasons for this change are explained here). To get the original functionality back, I also wrote two helper functions that takes only a width/height and fill in the missing parameter based on the aspect ratio of the passed image. The helper functions look like this: public static function imageResponsiveByWidth( Pageimage $img, ?int $standard_width = 0, ?array $attributes = [], ?array $sizes_queries = [], array $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2] ): string { // automatically fill the height parameter based // on the aspect ratio of the passed image if (empty($standard_width)) { $standard_width = $img->width(); } $factor = $img->height() / $img->width(); $standard_height = ceil($factor * $standard_width); return self::imageResponsive( $img, $standard_width, $standard_height, $attributes, $sizes_queries, $variant_factors ); } Conclusion This approach was born out of necessity, since pure PHP templating makes for some messy code. Of course, another approach would be to use a template engine in the first place. However, I didn't want the overhead of installing Twig or Blades for my smaller projects, so for those small to medium-sized projects, I found some helper functions to generate markup and clean up my code to be a helpful addition. A small disclaimer, I update those functions pretty frequently while developing with ProcessWire, so it's possible some errors made their way into the versions I posted here that I haven't discovered yet. If you want to use some of the included code in your own projects, make sure to properly test it. I'm also working on a small library including those and some other helpers I wrote, I'll post a Github link once it's in a usable stage. So this post got way longer than I intended, I hope that some of you still made your way through it and enjoyed it a bit ? If you see some problems or possible improvements to those methods and the general approach, I'd be happy to hear them! Complete code for reference <?php use \Processwire\Pageimage; class Html { /** * Build a simple element tag with the passed element. * * @param string $element The element/tag name as a string. * @param ?string $content The content of the element (what goes between the tags). * @param ?array $attributes Optional attributes for the element. * @param boolean $self_closing Whether the element is self-closing (i.e. no end tag). $content is ignored if true. * @return string The HTML element markup. */ public static function element( string $element, ?string $content = null, array $attributes = [], $self_closing = false ): string { if ($self_closing) { return self::startTag($element, $attributes); } else { return self::startTag($element, $attributes) . $content . self::endTag($element); } } /** * Builds a start tag for an element (or a self-closing/void element). * * @param string $element * @param array $attributes * @return string The HTML start tag markup. */ public static function startTag( string $element, ?array $attributes = [] ): string { $attribute_string = self::attributes($attributes, true); return "<{$element}{$attribute_string}>"; } /** * Build an end tag for an element. * * @param string $element The HTML end tag markup. * @return void */ public static function endTag(string $element): string { return "</{$element}>"; } /** * Build an HTML attribute string from an array of attributes. Attributes set * to (bool) true will be included as standalone (no attribute value) and left * out if set to (bool) false. * * @param array $attributes Attributes in attribute => value form. * @param bool $leading_space Whether to include a leading space in the attribute string. * @return string The attributes as html markup. */ public static function attributes( array $attributes, bool $leading_space = false ): string { $attr_string = ''; foreach ($attributes as $attr => $val) { if (is_bool($val)) { if ($val) { $attr_string .= " $attr"; } } else { $attr_string .= ' ' . $attr . '="' . $val . '"'; } } if (!$leading_space) { $attr_string = ltrim($attr_string, ' '); } return $attr_string; } /** * Image Functions. */ /** * Build a simple image tag from a Processwire Pageimage object. * * @param Pageimage $img The image to use. * @param array $attributes Optional attributes for the element. * @return string */ public static function image(Pageimage $img, array $attributes = []): string { $attributes['src'] = $img->url(); // use image description as alt text, unless specified in $attributes if (empty($attributes['alt']) && !empty($img->description())) { $attributes['alt'] = $img->description(); } return self::selfClosingElement('img', $attributes); } /** * Builds a responsive image element including different resolutions * of the passed image and optionally a sizes attribute build from * the passed queries. * * @param Pageimage $img The base image. Must be passed in the largest size available. * @param int|null $standard_width The standard width for the generated image. Use NULL to use the inherent size of the passed image. * @param int|null $standard_height The standard height for the generated image. Use NULL to use the inherent size of the passed image. * @param array|null $attributes Optional array of html attributes. * @param array|null $sizes_queries The full queries and sizes for the sizes attribute. * @param array|null $variant_factors The multiplication factors for the alternate resolutions. * @return string */ public static function imageResponsive( Pageimage $img, ?int $standard_width = 0, ?int $standard_height = 0, ?array $attributes = [], ?array $sizes_queries = [], array $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2] ): string { // use inherit dimensions of the passed image if standard width/height is empty if (empty($standard_width)) { $standard_width = $img->width(); } if (empty($standard_height)) { $standard_height = $img->height(); } $suffix = 'auto_srcset'; // if $attributes is null, default to an empty array $attributes = $attributes ?? []; // get original image for resizing $original_image = $img->getOriginal() ?? $img; // the default image for the src attribute $default_image = $original_image->size( $standard_width, $standard_height, ['upscaling' => false, 'suffix' => $suffix] ); // build the srcset attribute string, and generate the corresponding widths $srcset = []; foreach ($variant_factors as $factor) { // round up, srcset doesn't allow fractions $width = ceil($standard_width * $factor); $height = ceil($standard_height * $factor); // we won't upscale images if ($width <= $original_image->width() && $height <= $original_image->height()) { $current_image = $original_image->size($width, $height, ['upscaling' => false, 'suffix' => $suffix]); $srcset[] = $current_image->url() . " {$width}w"; } } $attributes['srcset'] = implode(', ', $srcset); // build the sizes attribute string if ($sizes_queries) { $attributes['sizes'] = implode(', ', $sizes_queries); } return self::image($default_image, $attributes); } /** * Shortcut for the responsiveImage function that only takes a width parameter. * Height is automatically generated based on the aspect ratio of the passed image. * * @param Pageimage $img The base image. Must be passed in the largest size available. * @param int|null $standard_width The standard width for this image. Use NULL to use the inherent size of the passed image. * @param array|null $attributes Optional array of html attributes. * @param array|null $sizes_queries The full queries and sizes for the sizes attribute. * @param array|null $variant_factors The multiplication factors for the alternate resolutions. * @return string */ public static function imageResponsiveByWidth( Pageimage $img, ?int $standard_width = 0, ?array $attributes = [], ?array $sizes_queries = [], array $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2] ): string { // automatically fill the height parameter based // on the aspect ratio of the passed image if (empty($standard_width)) { $standard_width = $img->width(); } $factor = $img->height() / $img->width(); $standard_height = ceil($factor * $standard_width); return self::imageResponsive( $img, $standard_width, $standard_height, $attributes, $sizes_queries, $variant_factors ); } /** * Shortcut for the responsiveImage function that only takes a height parameter. * Width is automatically generated based on the aspect ratio of the passed image. * * @param Pageimage $img The base image. Must be passed in the largest size available. * @param int|null $standard_height The standard height for this image. Use NULL to use the inherent size of the passed image. * @param array|null $attributes Optional array of html attributes. * @param array|null $sizes_queries The full queries and sizes for the sizes attribute. * @param array|null $variant_factors The multiplication factors for the alternate resolutions. * @return string */ public static function imageResponsiveByHeight( Pageimage $img, ?int $standard_height = 0, ?array $attributes = [], ?array $sizes_queries = [], array $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2] ): string { // automatically fill the width parameter based // on the aspect ratio of the passed image if (empty($standard_height)) { $standard_height = $img->height(); } $factor = $img->width() / $img->height(); $standard_width = ceil($factor * $standard_height); return self::imageResponsive( $img, $standard_width, $standard_height, $attributes, $sizes_queries, $variant_factors ); } }
    4 points
  3. Not easy using the core Datetime field type alone AFAIK. The DatetimeAdvanced module by @BitPoet supports querying by month, but see the notes about timezone support in the module readme. An alternative would be to add a hidden integer field to the template and save the month number to that in a saveReady hook, then use that field in your selector.
    4 points
  4. That's correct, I barely think about that anymore since I'm able to write PHP 7.2 at work ^^' Thanks! I'm working on that, though at the moment I'm just building it as a generic composer package. Just seems easy since you get to use the composer autoloader ... I haven't found a simple way to autoload classes in a Processwire module, and performance-wise I don't like the idea of including everything on every request. That nette module is interesting, I actually started building something like that at first, but it turned out to be more overhead than I needed most of the time. Though the nette module seems much simpler than my first approach, so maybe I gave up too quickly ... How would you include another library such as nette in a Processwire module? Manually or is there a more Processwire-y way to include dependencies?
    3 points
  5. Very nice tutorial, thx! I wonder if that would be nice to have as a module. Installable, reusable, one-click-updateable.... But maybe it would be easier to extend available libraries, such as https://doc.nette.org/en/2.4/html-elements
    3 points
  6. Really great tutorial, thanks! Might be worth noting that a minimum of PHP 7.1 is required for the code syntax used.
    3 points
  7. Attention: please don't install this module at the time being! It is not compatible with current PW versions, and it will be some time until I can work in all the changes. Due to a discussion here in the forums, I was inspired to finally have a take on datetime fields and see if I couldn't get them to be searched a little more conveniently. Here's a small module - still in alpha state, but I'd be happy to get some feedback - that allows searching for individual components of a date like year, month, day, hour or even day_of_week or day_of_year, and also returning them. Github repo: DatetimeAdvanced Current version: 0.0.5 Tested in: ProcessWire 2.8 + 3.0 Possible subfields: day month year hour minute second day_of_week day_of_year week_of_year Examples: // Database search: $pagelist = $pages->find("mydatefield.year=2016"); // Filtering PageArray in memory: $maypages = $pagelist->filter("mydatefield.month=5"); // Back to our starting point: $start = date('z'); $end = $start + 7; $sevendays = $pages->find("mydatefield.day_of_year>=$start, mydatefield.day_of_year<$end"); // Nice side effect: subfields are now directly accessible $blogentry = $pages->get('blog-entry-1'); echo $blogentry->title . "(" . $blogentry->publishdate->year . ")"; // New in 0.0.4: shorthand methods echo $blogentry->publishdate->strftime("%Y-%m-%d %H:%M:%S") . PHP_EOL; echo $blogentry->publishdate->date("Y-m-d H:i:s") . PHP_EOL; ToDos for the future: See if there's a possibility to specify ranges more conveniently Check if this can perhaps wiggle its way into the PW core Changes: example for direct subfield access and shorthand methods to strftime() and date() added.
    2 points
  8. Maybe this will help? http://cheatsheet.processwire.com/files/file-properties/
    2 points
  9. Something like this would be the easiest way, I can think of, to do what you are doing. Redirect to a another language, including urlSegments, Pagenumber and optional QueryStrings; if($user->language->isDefault) { $user->language = $languages->get("de"); $session->redirect($input->url($withQueryString = true)); }
    2 points
  10. Another idea depending the number of data you got (anyway, not really a criteria here), you could also use RockFinder by @bernhard and custom queries using MySQL EXTRACT function with subquery. # pseudo-query SELECT pages.id FROM ( sub_query ) WHERE EXTRACT(MONTH FROM DATE( subquery_here ) ); https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_extract
    2 points
  11. Just a short update: if MySQL (or the OS it's running on) and PHP are configured with different time zones, results will be wrong. You'll likely not notice anything off on local dev environments where everything is configured with the same time zone, but to prevent issues on deployment, MySQL needs to be made timezone-aware and PW's database connections need to tell MySQL which timezone to use for conversions, which should IMHO be done through a not-yet-existing $config property. That's why I've filed feature request #19. I'm now holding my fingers crossed and waiting to hear if it gets considered. This will mean that, assuming it does, the module will require at least the PW version that gets the new $config property.
    2 points
  12. When you change the $user->language, all following API returns stuff in that language also, the $page->url or $input->url. No need to do str_eplace on something already the same. So if $this.>getLangFromCookie does return the language object then you can change it to this. private function doInitLocalization() { $user = wire('user'); $input = wire('input'); // Get/set user language from either browser or cookie $language = $this->getLangFromCookie() ?: $this->getValidBrowserPrefLang(); if($language !== $user->language) { $user->language = $language; $this->wire("session")->redirect($input->url(true)); } }
    1 point
  13. In the getSelectablePages() hook $event->arguments('page') is the page being edited, but that is not so useful in your case because what you want is the Repeater page that contains the two Page Reference fields. Give this a try: $wire->addHookAfter('InputfieldPage::getSelectablePages', function(HookEvent $event) { if($event->object->hasField == 'people') { $inputfield = $event->object; $repeater_page = $inputfield->hasPage; if($repeater_page->team && $repeater_page->team->id) { $event->return = $event->pages->find("template=user, team=$repeater_page->team"); } } }); Note that if the user changes the selection for the team field they will need to save the page before the selectable options for the people field will update.
    1 point
  14. How about getting the url-segments/page-num/get-vars suffix and then appending that to $page->localUrl? $url_suffix = str_replace($page->url, '', $input->url(true)); $redirect_url = $page->localUrl() . $url_suffix;
    1 point
  15. Hi Zeka and dragan, thanks a lot for your answers! I found out that changing the order of the language pages in Admin > Setup > Languages caused the problem. I had changed the order a while ago. As soon as I moved the default language (english) back to the first position, the tabs looked ok again. I don't know why that happens. Anyways, thanks a lot for your help!
    1 point
  16. A bit of an update after some more experimentation tonight. I added pages.templates_id as a field always selected in the RockFinder results, and then attempted to use the $pages->newPage() method to take the results of the SQL query and convert them into a PageArray of Page objects. This worked, thus eliminating that second trip to the database I mentioned (and also bypassing the page cache and probably some other nice features of the normal page creation process). Unfortunately, this slowed the whole thing way down again. So I'm thinking now that it is something else about constructing Pages that is slow. Maybe generating the page path or some other properties are the problem. Perhaps I need to load up some additional fields up front. Will have to test more. WireData/WireArray works great, though.
    1 point
  17. https://github.com/processwire/processwire/blob/master/wire/config.php#L777 https://github.com/processwire/processwire/blob/master/wire/config.php#L788 But I think that the best route is to update your URLs and make redirects in Jumplinks.
    1 point
  18. Thank you... sounds like a cool idea. The textformatter would not be the way to go for me as I - in general - like PW's pagefileSecure feature. Right now I am thinking of a workaround (not tested yet). Since the pagefileSecure blocking is only active on (1. pages that are hidden from "guest" users by rights restrictions (or 2. pages are unpublished), I will try to publish some innocent blank page that remains visible to users and load the needed images there into some file field in the backend. Then I would reference those (not blocked) images in the textarea of the PDF source page - and the rights problem is maybe bypassed.
    1 point
  19. @Ralf Which PHP version are you using? "self::new" is a syntax that threw an error prior to PHP 7. Since PW minimum requirements is PHP 5.3 it is a bug introduced in version 3.0.117. Like @adrian said, reverting to 3.0.116 or upgrading to PHP >=7.0 should fix it. Anyway, I would also like to use this comment to continue a discussion that started in the comments sections of the blog post about the newly introduced WireArray::new() static method. I posted a pretty long comment about that which never got published. (As a side node, that is highly frustrating, taking into account I took quite some time researching background information to the comment I made. So here is going to be a shorter version of that post) The discussion started with @teppo and @bernhard asking, why a new concept of WireArray::new() was introduced to initialise a new WireArray with data. More intuitive would be if you could just initialise it using new WireArray() and pass your data to the constructor. That's how it works for most other objects in ProcessWire too. To that @ryan replied: Now, I do understand why this is necessary, but just like Teppo and Bernhard I'm not 100% happy with it. It seems like a small thing we shouldn't care too much about, but I came to love ProcessWire because I usually do things I learned them using plain PHP and most of the time they just work the way I expect it. This new WireArray::new syntax is something I would intuitevly do wrong, then wonder why it doesn't work, then search the documentation, and finally ask myself, why I can't just use new WireArray(). And that's a workflow that's slowing me as a developer down, a workflow I'm accustomed to from Wordpress, not from ProcessWire. So although it doesn't seem like a big thing, is there a chance we could make new WireArray() work for initialising WireArray objects with data? As far as I could see there are four classes derived from WireArray and implementing their own constructor. Would it be possible to refactor those?
    1 point
  20. I usually use english names for the templates and fields (german websites). I think everybody understands that ?
    1 point
  21. Thanks to everyone who was helping me the other night. A little update on what I ended up doing with my helper module so far.... For the site settings, I ended up just making a configurable module with only one field containing a load of defaults stored as a simple JSON array. I thought this would be far easier for my specific purpose as it means that it's easily customisable with new data on a site-by-site basis without having to update the module interface or add new fields. I've hooked the $page object to access this data on the front end, so I can now do <?=$page->siteSettings['company_name'];?> etc in my templates which is cool. I've also set some dependencies in the config for the modules we regularly use. I have also used a hook to inject an overlay 'edit mode' icon that displays on the front end whenever an editor is logged into the site, as we've found some people don't realise when they're logged in and can use the front-end editing on their site. The little cog icon also links back to the PW dashboard. Really starting to get the hang of how the PW modules work now, so will be adding in lots more useful stuff we tend to use for every project in due course. ?
    1 point
  22. I can see it on my install (although I installed it before upgrading to PW 3.0.117). What Theme are you using?
    1 point
  23. @Ralf - I would recommend installing 3.0.116 for the moment. It looks like this is not the only bug introduced in 3.0.117 - the Profields Table field is also throwing warnings that need attention. Note that there is no 3.0.118 yet
    1 point
  24. Here's a preview of the new API Explorer panel I hinted at earlier. You'll notice a lot of similarities with the Captain Hook Panel with everything ordered alphabetically, and with toggling to open/close the DocComment text and direct links to open the appropriate file to the first line of the method in your code editor which I hope will be a useful learning tool because often the methods for an object are inherited from a parent class and so are not necessarily in the file you might expect. This will make finding the source of these methods really quick and easy. The link in the first column of the table opens the API ref docs on the PW site or using Ryan's API Explorer module (if you have that installed). Also note that conditional parameters for the methods are italicized I'll probably commit the first version of this tomorrow, but I'd love to hear any initial feedback from these screenshots - other than comments on the awful icon ? (unless you have a suggestion for a better one).
    1 point
  25. Try switching / updating the admin-theme(s).
    1 point
  26. @tron1000 Do you have any js errors on page? Have you tried to clean the browser cache?
    1 point
  27. Hi everybody! And thanks for Processwire! The Leaflet Map module appears to have the same issue that the gmap-based Map Marker Map module. The map will not render if placed inside ajax-driven repeater item as one of its data fields because there's no leaflet map initialization after the ajax call. Here's a small fix to be added at the bottom of InputfieldLeafletMapMarker.js file: //A patch for displaying the map inside ajax repeater items $(".InputfieldHeader").on('click',function(event) { window.setTimeout(function(){ var $t = $(event.target).siblings('.InputfieldContent').find('.InputfieldLeafletMapMarkerMap'); InputfieldLeafletMapMarker.init($t.attr('id'), $t.attr('data-lat'), $t.attr('data-lng'), $t.attr('data-zoom'), $t.attr('data-type'), $t.attr('data-provider')); },500); }); }); The delay is rather arbitrary, 500 ms works for me.
    1 point
  28. It depends on how big is big. In one of our bigger projects, we designed the whole system around ProcessWire's page-templates-fields paradigm. It was designed in such a ways that it looked almost like a normalized relational database with PageReference providing the "relationships", but with each page easily editable in the admin. This was working well, until it wasn't. I'm guessing it was because we "normalized" the data too much that we were hit with performance issues when we started making big queries specially with aggregates, and with traversals. Of course this wasn't ProcessWire's fault but our own because we wanted so much to be able to code using mostly PWs API and very minimal raw SQL. Our intermediate fix was to write the queries manually to make the huge queries. But after a while the solution felt dirty, so in the end we refactored our data, pulled them out of ProcessWire's database and moved them to a separate database. We used a half-and-half ORM solution to access the data and wrote custom modules to edit them on the backend as @Macrura suggested. So what I'm trying to say TL;DR is: If you want to use PW to manage your database, it'll be great. It's not how "big" your data is, but how complex the relationships will be. And maybe not even that. It depends on how much you want to rely on the API to get your data. We were doing all well and good until we wanted to get something like $page->parent->child->children()->child on some reports, or something similar which of course resulted in hundreds of JOINS. (Don't do that, seriously, we were stupid. Lazy and stupid ). But if it's something where you're doing huge queries and reports, it will work but it will not be the fastest unless you start writing custom SQL queries. If you're lazy like me, use an ORM if you decide to use a separate database. But this of course will have an overhead in learning curve and in writing the custom modules for the admin. I hope this helps. :/
    1 point
  29. Since there are a lot of topics about the same theme, I decided to write a small module which overwrites the core function ___SetupPageName(). The module allows now to populate the page name using proprietary date() function. Works like PHP date() with follwing exceptions: Everything between the brackets is detected as format string, meaning no 2nd parameter possible. No need to use quotes around the format string. Spaces not allowed. from any page property, page field including subfields, parent property, parent field etc. Meaning everything what you get with $page->get(); including dot syntax. The function will give error and warnings in case of unproper settings, but creates the page with name 'untitled' anyway. Download here: http://modules.processwire.com/modules/process-setup-page-name/ Some Examples The following settings in parent template 'Name Format Children' will assign name immediately. date(Y) date('Y-m-d') parent.title parent.parent.title parent.id template.id assign name after page saving and/or population of depending field. Overwrites 'untitled' after all fields which are defined in parent template are populated. id (any other page property) pagefieldname, multiple pagefieldnames show a warning. pagefieldname (value not populated)show an error. date() // empty, no format assigned date(Y // missing closing bracket date(Y md) // unallowed space notexistingfieldname notexistingproperty existingfield.notexistingsubfield The function in the module ___SetupPageName() could be completely copied as is to the core class $pages. @Ryan Would be nice to see this in core. Related topics: https://processwire.com/talk/topic/8576-name-format-children/ https://processwire.com/talk/topic/8217-name-format-for-children-based-on-any-field-not-just-title/ https://processwire.com/talk/topic/11628-custom-page-name/ https://processwire.com/talk/topic/11349-page-add-step-not-being-skipped-when-name-format-for-children-is-set/ https://processwire.com/talk/topic/10701-automatic-page-name-using-processpageaddexecute-and-pagetable/ https://processwire.com/talk/topic/10208-pagetable-automatic-page-name-format-when-multiple-templates-allowed/ https://processwire.com/talk/topic/9979-name-format-for-children-for-multiple-allowed-templates-for-children/ https://processwire.com/api/modules/process-template/ Any recommandations after testing welcome. Download here: Download here: http://modules.processwire.com/modules/process-setup-page-name/ Edit: small enhancement to prevent display of warning twice. 23.12.15 multiple values possible now 24.12.15 made compatible with PW 3.x 27.12.15 Update Version 1.0.8 09.01.16 Update Version 1.1.0
    1 point
  30. What Martin said two posts above - for folks looking for some familiarity moving from MODx, the Hanna Code module is definitely your friend as its really powerful and you can use these codes inside any textarea field that you have set to parse Hanna Codes.
    1 point
×
×
  • Create New...