Jump to content

Search the Community

Showing results for 'strong'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

  1. Hi everyone, we’d like to share a small but handy module we developed at frameless Media: TextformatterSmartQuotes. 🧠 The Problem While working on a client project, we needed to replace straight quotes ("...") with typographic quotes (like „...“) — but only in the visible text content, not inside HTML tags or attributes. Using the TextformatterFindReplace module, a case like this: <strong style="font-size: 18px;">Improved "well-being"</strong> would turn into: <strong style=„font-size: 18px;“>Improved „well-being“</strong> which breaks the HTML. We tried solving it with regular expressions, but none proved reliable enough. Every approach either failed to match all valid cases or accidentally modified tag attributes. That’s when we decided to build a dedicated solution. ✅ Our Solution TextformatterSmartQuotes is a Textformatter that replaces quotes only in visible text, leaving HTML markup untouched. It supports the following quote styles: German: „…“ English: “…” French: « … » The quote style can be selected in the module’s settings. 📦 Installation Place the module in /site/modules/TextformatterSmartQuotes/. Install it via the Modules admin interface. Assign it to any text/textarea/CKEditor field under “Text formatters”. Configure your preferred quote style if needed. This module helped us avoid fragile regex workarounds and keeps content formatting clean and reliable. Feel free to use, improve, or contribute to it. You can download it on GitHub or via the Modules Directory We’re happy to hear your feedback! Cheers, Mike
  2. Hi @Nomak I am interested in assisting with the frontend development of your website. I have experience building responsive websites using HTML, CSS, and JavaScript, with strong attention to clean code, performance, and cross-device compatibility. I understand that the design is already finalized. I can focus entirely on implementing the frontend according to the provided layouts and ensuring full responsiveness across desktop, tablet, and mobile devices. Please feel free to share the design files and any technical requirements or timelines. Happy to discuss the project further. Good Day Deep
  3. I really like the way things are going with ProcessWire and AI. Thank you, Ryan. I've been a big fan and strong advocate for migrations in PW, since I started using RockMigrations years ago. What makes RM a particularly strong candidate is the abstraction into a schema-like format which is much easier to understand/read/write than native PW API code. This is a real strength of RM and I would prefer a schema-based approach anytime over writing (or having AI write) PW API code. Claude is very good at understanding the PW API, other models are not that strong. But they all can understand schemata. Be it PHP arrays, JSON, YAML. So I would advocate for either developing an "official" PW migration schema or adapting the existing, battle tested one from RockMigrations.
  4. Wow. These "ProcessWire as a web application framework"-type updates are coming in strong! Migrations, CLI, Tests, AI. One can wish for a maybe first party queue system too. 😄
  5. Aider has an interesting “architect mode”, where you can define a “strong” and a “week” models for reasoning and acting. This can keep costs much lower https://aider.chat/2024/09/26/architect.html
  6. --------------------------------------------------------------------------------------------------------------------------------- when working with PW version 2.6+, please use Pim2, not Pim! read more here on how to change from the older to the newer version in existing sites --------------------------------------------------------------------------------------------------------------------------------- PageImage Manipulator, API for version 1 & 2 The Page Image Manipulator is a module that let you in a first place do ImageManipulations with your PageImages. - And in a second place there is the possibility to let it work on any imagefile that exists in your servers filesystem, regardless if it is a 'known PW-image'. The Page Image Manipulator is a Toolbox for Users and Moduledevelopers. It is written to be as close to the Core ImageSizer as possible. Besides the GD-filterfunctions it contains resize, crop, canvas, rotate, flip, sharpen, unsharpMask and 3 watermark methods. How does it work? You can enter the ImageManipulator by calling the method pim2Load(). After that you can chain together how many actions in what ever order you like. If your manipulation is finished, you call pimSave() to write the memory Image into a diskfile. pimSave() returns the PageImage-Object of the new written file so we are able to further use any known PW-image property or method. This way it integrates best into the ProcessWire flow. The three examples above put out the same visual result: a grayscale image with a width of 240px. Only the filenames will slightly differ. You have to define a name-prefix that you pass with the pimLoad() method. If the file with that prefix already exists, all operations are skipped and only the desired PageImage-Object gets returned by pimSave(). If you want to force recreation of the file, you can pass as second param a boolean true: pim2Load('myPrefix', true). You may also want to get rid of all variations at once? Than you can call $pageimage->pim2Load('myPrefix')->removePimVariations()! A complete list of all methods and actions are at the end of this post. You may also visit the post with tips & examples for users and module developers. How to Install Download the module Place the module files in /site/modules/PageImageManipulator/ In your admin, click Modules > Check for new modules Click "install" for PageImageManipulator Done! There are no configuration settings needed, just install and use it. Download (version 0.2.0) get it from the Modules Directory History of origins http://processwire.com/talk/topic/3278-core-imagemanipulation/ ---------------------------------------------------------------------------------------------------------- Page Image Manipulator - Methods * pimLoad or pim2Load, depends on the version you use! pimLoad($prefix, $param2=optional, $param3=optional) param 1: $prefix - (string) = mandatory! param 2: mixed, $forceRecreation or $options param 3: mixed, $forceRecreation or $options return: pim - (class handle) $options - (array) default is empty, see the next method for a list of valid options! $forceRecreation - (bool) default is false It check if the desired image variation exists, if not or if forceRecreation is set to true, it prepares all settings to get ready for image manipulation ------------------------------------------------------------------- * setOptions setOptions(array $options) param: $options - (array) default is empty return: pim - (class handle) Takes an array with any number valid options / properties and set them by replacing the class-defaults and / or the global config defaults optionally set in the site/config.php under imageSizerOptions or imageManipulatorOptions. valid options are: quality = 1 - 100 (integer) upscaling = true | false (boolean) cropping = true | false (boolean) autoRotation =true | false (boolean) sharpening = 'none' | 'soft' | 'medium' | 'strong' (string) bgcolor = (array) css rgb or css rgba, first three values are integer 0-255 and optional 4 value is float 0-1, - default is array(255,255,255,0) thumbnailColorizeCustom = (array) rgb with values for colorize, integer -255 - 255 (this can be used to set a custom color when working together with Thumbnails-Module) outputFormat = 'gif' | 'jpg' | 'png' (Attention: outputFormat cannot be specified as global option in $config->imageManipulatorOptions!) set {singleOption} ($value) For every valid option there is also a single method that you can call, like setQuality(90), setUpscaling(false), etc. ------------------------------------------------------------------- * pimSave pimSave() return: PageImage-Object If a new image is hold in memory, it saves the current content into a diskfile, according to the settings of filename, imagetype, targetFilename and outputFormat. Returns a PageImage-Object! ------------------------------------------------------------------- * release release() return: void (nothing) if you, for what ever reason, first load image into memory but than do not save it, you should call release() to do the dishes! ? If you use pimSave() to leave the ImageManipulator, release() is called automatically. ------------------------------------------------------------------- * getOptions getOptions() return: associative array with all final option values example: ["autoRotation"] bool(true) ["upscaling"] bool(false) ["cropping"] bool(true) ["quality"] int(90) ["sharpening"] string(6) "medium" ["targetFilename"] string(96) "/htdocs/site/assets/files/1124/pim_prefix_filename.jpg" ["outputFormat"] string(3) "jpg" get {singleOption} () For every valid option there is also a single method that you can call, like getQuality(), getUpscaling(), etc. See method setOptions for a list of valid options! ------------------------------------------------------------------- * getImageInfo getImageInfo() return: associative array with useful informations of source imagefile example: ["type"] string(3) "jpg" ["imageType"] int(2) ["mimetype"] string(10) "image/jpeg" ["width"] int(500) ["height"] int(331) ["landscape"] bool(true) ["ratio"] float(1.5105740181269) ["bits"] int(8) ["channels"] int(3) ["colspace"] string(9) "DeviceRGB" ------------------------------------------------------------------- * getPimVariations getPimVariations() return: array of Pageimages Collect all pimVariations of this Pageimage as a Pageimages array of Pageimage objects. All variations created by the core ImageSizer are not included in the collection. ------------------------------------------------------------------- * removePimVariations removePimVariations() return: pim - (class handle) Removes all image variations that was created using the PIM, all variations that are created by the core ImageSizer are left untouched! ------------------------------------------------------------------- * width width($dst_width, $sharpen_mode=null) param: $dst_width - (integer) param: $auto_sharpen - (boolean) default is true was deleted with version 0.0.8, - sorry for breaking compatibility param: $sharpen_mode - (string) possible: 'none' | 'soft' | 'medium' | 'strong', default is 'soft' return: pim - (class handle) Is a call to resize where you prioritize the width, like with pageimage. Additionally, after resizing, an automatic sharpening can be done with one of the three modes. ------------------------------------------------------------------- * height height($dst_height, $sharpen_mode=null) param: $dst_height - (integer) param: $auto_sharpen - (boolean) default is true was deleted with version 0.0.8, - sorry for breaking compatibility param: $sharpen_mode - (string) possible: 'none' | 'soft' | 'medium' | 'strong', default is 'soft' return: pim - (class handle) Is a call to resize where you prioritize the height, like with pageimage. Additionally, after resizing, an automatic sharpening can be done with one of the three modes. ------------------------------------------------------------------- * resize resize($dst_width=0, $dst_height=0, $sharpen_mode=null) param: $dst_width - (integer) default is 0 param: $dst_height - (integer) default is 0 param: $auto_sharpen - (boolean) default is true was deleted with version 0.0.8, - sorry for breaking compatibility param: $sharpen_mode - (string) possible: 'none' | 'soft' | 'medium' | 'strong', default is 'soft' return: pim - (class handle) Is a call to resize where you have to set width and / or height, like with pageimage size(). Additionally, after resizing, an automatic sharpening can be done with one of the three modes. ------------------------------------------------------------------- * stepResize stepResize($dst_width=0, $dst_height=0) param: $dst_width - (integer) default is 0 param: $dst_height - (integer) default is 0 return: pim - (class handle) this performs a resizing but with multiple little steps, each step followed by a soft sharpening. That way you can get better result of sharpened images. ------------------------------------------------------------------- * sharpen sharpen($mode='soft') param: $mode - (string) possible values 'none' | 'soft'| 'medium'| 'strong' return: pim - (class handle) Applys sharpening to the current memory image. You can call it with one of the three predefined pattern, or you can pass an array with your own pattern. ------------------------------------------------------------------- * unsharpMask unsharpMask($amount, $radius, $threshold) param: $amount - (integer) 0 - 500, default is 100 param: $radius - (float) 0.1 - 50, default is 0.5 param: $threshold - (integer) 0 - 255, default is 3 return: pim - (class handle) Applys sharpening to the current memory image like the equal named filter in photoshop. Credit for the used unsharp mask algorithm goes to Torstein Hønsi who has created the function back in 2003. ------------------------------------------------------------------- * smooth smooth($level=127) param: $level - (integer) 1 - 255, default is 127 return: pim - (class handle) Smooth is the opposite of sharpen. You can define how strong it should be applied, 1 is low and 255 is strong. ------------------------------------------------------------------- * blur blur() return: pim - (class handle) Blur is like smooth, but cannot called with a value. It seems to be similar like a result of smooth with a value greater than 200. ------------------------------------------------------------------- * crop crop($pos_x, $pos_y, $width, $height) param: $pos_x - (integer) start position left param: $pos_y - (integer) start position top param: $width - (integer) horizontal length of desired image part param: $height - (integer) vertical length of desired image part return: pim - (class handle) This method cut out a part of the memory image. ------------------------------------------------------------------- * canvas canvas($width, $height, $bgcolor, $position, $padding) param: $width = mixed, associative array with options or integer, - mandatory! param: $height = integer, - mandatory if $width is integer! param: $bgcolor = array with rgb or rgba, - default is array(255, 255, 255, 0) param: $position = one out of north, northwest, center, etc, - default is center param: $padding = integer as percent of canvas length, - default is 0 return: pim - (class handle) This method creates a canvas according to the given width and height and position the memory image onto it. You can pass an associative options array as the first and only param. With it you have to set width and height and optionally any other valid param. Or you have to set at least width and height as integers. Hint: If you want use transparency with rgba and your sourceImage isn't of type PNG, you have to define 'png' as outputFormat with your initially options array or, for example, like this: $image->pimLoad('prefix')->setOutputFormat('png')->canvas(300, 300, array(210,233,238,0.5), 'c', 5)->pimSave() ------------------------------------------------------------------- * flip flip($vertical=false) param: $vertical - (boolean) default is false return: pim - (class handle) This flips the image horizontal by default. (mirroring) If the boolean param is set to true, it flips the image vertical instead. ------------------------------------------------------------------- * rotate rotate($degree, $backgroundColor=127) param: $degree - (integer) valid is -360 0 360 param: $backgroundColor - (integer) valid is 0 - 255, default is 127 return: pim - (class handle) This rotates the image. Positive values for degree rotates clockwise, negative values counter clockwise. If you use other values than 90, 180, 270, the additional space gets filled with the defined background color. ------------------------------------------------------------------- * brightness brightness($level) param: $level - (integer) -255 0 255 return: pim - (class handle) You can adjust brightness by defining a value between -255 and +255. Zero lets it unchanged, negative values results in darker images and positive values in lighter images. ------------------------------------------------------------------- * contrast contrast($level) param: $level - (integer) -255 0 255 return: pim - (class handle) You can adjust contrast by defining a value between -255 and +255. Zero lets it unchanged, negative values results in lesser contrast and positive values in higher contrast. ------------------------------------------------------------------- * grayscale grayscale() return: pim - (class handle) Turns an image into grayscale. Remove all colors. ------------------------------------------------------------------- * sepia sepia() return: pim - (class handle) Turns the memory image into a colorized grayscale image with a predefined rgb-color that is known as "sepia". ------------------------------------------------------------------- * colorize colorize($anyColor) param: $anyColor - (array) like css rgb or css rgba - but with values for rgb -255 - +255, - value for alpha is float 0 - 1, 0 = transparent 1 = opaque return: pim - (class handle) Here you can adjust each of the RGB colors and optionally the alpha channel. Zero lets the channel unchanged whereas negative values results in lesser / darker parts of that channel and higher values in stronger saturisation of that channel. ------------------------------------------------------------------- * negate negate() return: pim - (class handle) Turns an image into a "negative". ------------------------------------------------------------------- * pixelate pixelate($blockSize=3) param: $blockSize - (integer) 1 - ??, default is 3 return: pim - (class handle) This apply the well known PixelLook to the memory image. It is stronger with higher values for blockSize. ------------------------------------------------------------------- * emboss emboss() return: pim - (class handle) This apply the emboss effect to the memory image. ------------------------------------------------------------------- * edgedetect edgedetect() return: pim - (class handle) This apply the edge-detect effect to the memory image. ------------------------------------------------------------------- * getMemoryImage getMemoryImage() return: memoryimage - (GD-Resource) If you want apply something that isn't available with that class, you simply can check out the current memory image and apply your image - voodoo - stuff ------------------------------------------------------------------- * setMemoryImage setMemoryImage($memoryImage) param: $memoryImage - (GD-Resource) return: pim - (class handle) If you are ready with your own image stuff, you can check in the memory image for further use with the class. ------------------------------------------------------------------- * watermarkLogo watermarkLogo($pngAlphaImage, $position='center', $padding=2) param: $pngAlphaImage - mixed [systemfilepath or PageImageObject] to/from a PNG with transparency param: $position - (string) is one out of: N, E, S, W, C, NE, SE, SW, NW, - or: north, east, south, west, center, northeast, southeast, southwest, northwest default is 'center' param: $padding - (integer) 0 - 25, default is 5, padding to the borders in percent of the images length! return: pim - (class handle) You can pass a transparent image with its filename or as a PageImage to the method. If the watermark is bigger than the destination-image, it gets shrinked to fit into the targetimage. If it is a small watermark image you can define the position of it: NW - N - NE | | | W - C - E | | | SW - S - SE The easiest and best way I have discovered to apply a big transparency watermark to an image is as follows: create a square transparent png image of e.g. 2000 x 2000 px, place your mark into the center with enough (percent) of space to the borders. You can see an example here! The $pngAlphaImage get centered and shrinked to fit into the memory image. No hassle with what width and / or height should I use?, how many space for the borders?, etc. ------------------------------------------------------------------- * watermarkLogoTiled watermarkLogoTiled($pngAlphaImage) param: $pngAlphaImage - mixed [systemfilepath or PageImageObject] to/from a PNG with transparency return: pim - (class handle) Here you have to pass a tile png with transparency (e.g. something between 150-300 px?) to your bigger images. It got repeated all over the memory image starting at the top left corner. ------------------------------------------------------------------- * watermarkText watermarkText($text, $size=10, $position='center', $padding=2, $opacity=50, $trueTypeFont=null) param: $text - (string) the text that you want to display on the image param: $size - (integer) 1 - 100, unit = points, good value seems to be around 10 to 15 param: $position - (string) is one out of: N, E, S, W, C, NE, SE, SW, NW, - or: north, east, south, west, center, northeast, southeast, southwest, northwest default is 'center' param: $padding - (integer) 0 - 25, default is 2, padding to the borders in percent of the images length! param: $opacity- (integer) 1 - 100, default is 50 param: $trueTypeFont - (string) systemfilepath to a TrueTypeFont, default is freesansbold.ttf (is GPL & comes with the module) return: pim - (class handle) Here you can display (dynamic) text with transparency over the memory image. You have to define your text, and optionally size, position, padding, opacity for it. And if you don't like the default font, freesansbold, you have to point to a TrueTypeFont-File of your choice. Please have a look to example output: http://processwire.com/talk/topic/4264-release-page-image-manipulator/page-2#entry41989 ------------------------------------------------------------------- PageImage Manipulator - Example Output
  7. Hey everyone, on a recent client project we had to deal with a large number of Markdown files that needed to end up as regular HTML content on ProcessWire pages. Converting them manually or piping them through external tools wasn't an option – too many files, too tedious, and the content had to be stored as actual HTML in rich textfields, not just formatted at runtime. So we built a small module that handles this directly inside ProcessWire. How it works The module creates a file upload field (md_import_files) and a Repeater field (md_import_items) with a standard title field and a richtext body field (md_import_body) inside. The body field automatically uses TinyMCE if installed, otherwise CKEditor. You add both fields (md_import_files,md_import_items) to any template, upload your .md files, hit save – each file gets converted to HTML via PW's core TextformatterMarkdownExtra and stored as a separate Repeater item. The source filename goes into the items title, processed files are removed from the upload automatically. Template output The Repeater items are regular PW pages, so output is straightforward: foreach ($page->md_import_items as $item) { echo "<section>"; echo "<h2>{$item->title}</h2>"; echo "<div>{$item->md_import_body}</div>"; echo "</section>"; } Tag mappings One thing we needed right away: control over how certain Markdown elements end up in HTML. For example, #headings in Markdown become <h1> – but on most websites <h1> is reserved for the page title. The module has a simple config (Modules → Configure → Markdown Importer) where you define tag mappings, one per line: h1:h2 h2:h3 strong:b blockquote:aside hr:br This performs a simple 1:1 tag replacement after conversion, preserving all attributes. Works well for standalone or equivalent elements like headings, inline formatting, blockquotes, or void elements like hr:br. Note that it doesn't handle nested structures – mapping table:ul for example would only replace the outer <table> tag while leaving thead, tr, td etc. untouched. Requirements ProcessWire 3.0.0+ FieldtypeRepeater (core) TextformatterMarkdownExtra (core) GitHub: github.com/frameless-at/MarkdownImporter Modules Directory: https://processwire.com/modules/markdown-importer/ Happy to hear if anyone finds this useful or has suggestions for improvements. Cheers, Mike
      • 6
      • Like
      • Thanks
  8. Hi folks, I am currently in search for a new hosting solution for my processwire client-websites (40 websites) with a strong focus on loading performance. Right now, the websites are hosted on an old Hosteurope shared hosting with HDD - which is going to be closed down this year. The new cPanel shared hosting Hosteurope offers in order to replace the old one has some strange weaknesses/limitation (I have tested it deeply). So I am forced to leave Hosteurope after many many years. Right now, I am testing varios hosting provider - for various reasons it must be form Germany. For testing I am comparing a live-website running on my old Hosteurope shared hosting with a duplicate of the live-website running on the new hosting provider. The testing tool I am using: Pagespeed Insights (https://pagespeed.web.dev/) In the past weeks I have tested webgo.de's managed vServer with ssd/nvme. But it was really disappointing: the websites loading performance was weaker than on my old Hosteurope shared hosting. And, they didn't even managed to activate http2. So right now, I am testing the managed server from Hetzner (product name MA80 with really strong physical stats). Even here, the websites loading performance is weaker than on my old Hosteurope shared hosting. And so far, the Hetzner support didn't help me to configure the server the for more performance. I am no server expert, can anyone recommend a hosting solution that has a really good loading performance? Best Nomak
  9. Largely agree with this, but in my experience, it has depended on the (potential) client and their role and what CMS they are moving from. I think I should have made this qualifier because I agree with this. It does depend on the size of client and role the website plays in their business operations. @Peter Knight I think reliability is also a very strong key feature. Those coming from WordPress will be all too familiar with surprise downtime, plugin vs. core upgrade challenges, high update frequency, and overall complexity in maintenance. If as a website owner/maintainer you need to call a developer to fix a website regularly, or to even just update the site because you can't figure it out, then you're not taking into account the hidden costs. Add plugin subscriptions on top of that. As I've said elsewhere in the PW forums, I like WordPress- I make a lot of money off of it. I'm not shy about openly discussing pain points with clients because I have none to offer and they're well familiar with those they've had to live with. I think I mentioned this in another post/thread recently. A demo can do a lot of the talking. I think PW had one at some point(?) but it would benefit both developers and clients immensely now. You can skip the main ProcessWire site, and a lot of Q&A, by just saying "take a look". Yes. No. I don't think that there is a standalone repo for the new theme either. I think it would be really helpful to make that a standalone repo that can accept PRs. Having the theme wrapped into the core means that all fixes and updates have to go through the same channel as core. The issues repo has been much more busy after the new theme launched. While there are a lot of big suggestions and input, there are plenty of fixes and smaller suggestions that could be implemented via PRs and result in easier per-contribution review, faster iterations, and quality improvements.
  10. Wire Mail SMTP An extension to the (new) WireMail base class that uses SMTP-transport This module integrates EmailMessage, SMTP and SASL php-libraries from Manuel Lemos into ProcessWire. I use this continously evolved libraries for about 10 years now and there was never a reason or occasion not to do so. I use it nearly every day in my office for automated composing and sending personalized messages with attachments, requests for Disposition Notifications, etc. Also I have used it for sending personalized Bulkmails many times. The WireMailSmtp module extends the new email-related WireMail base class introduced in ProcessWire 2.4.1 (while this writing, the dev-branch only). Here are Ryans announcement. Current Version 0.8.0 (from 2024-09-25 -- initial version 0.0.1 was pushed on 2014-03-01) Changelog: https://github.com/horst-n/WireMailSmtp/blob/master/CHANGELOG.md Downlod: get it from the Modules Directory || fetch it from Github || or use the module-installer in PWs admin site modules panel with its class name "WireMailSmtp". Install and Configure Download the module into your site/modules/ directory and install it. In the config page you fill in settings for the SMTP server and optionaly the (default) sender, like email address, name and signature. You can test the smtp settings directly there. If it says "SUCCESS! SMTP settings appear to work correctly." you are ready to start using it in templates, modules or bootstrap scripts. Usage Examples The simplest way to use it: $numSent = wireMail($to, $from, $subject, $textBody); $numSent = wireMail($to, '', $subject, $textBody); // or with a default sender emailaddress on config page This will send a plain text message to each recipient. You may also use the object oriented style: $mail = wireMail(); // calling an empty wireMail() returns a wireMail object $mail->to($toEmail, $toName); $mail->from = $yourEmailaddress; // if you don't have set a default sender in config // or if you want to override that $mail->subject($subject); $mail->body($textBody); $numSent = $mail->send(); Or chained, like everywhere in ProcessWire: $mail = wireMail(); $numSent = $mail->to($toEmail)->subject($subject)->body($textBody)->send(); Additionaly to the basics there are more options available with WireMailSmtp. The main difference compared to the WireMail BaseClass is the sendSingle option. With it you can set only one To-Recipient but additional CC-Recipients. $mail = wireMail(); $mail->sendSingle(true)->to($toEmail, $toName)->cc(array('person1@example.com', 'person2@example.com', 'person3@example.com')); $numSent = $mail->subject($subject)->body($textBody)->send(); The same as function call with options array: $options = array( 'sendSingle' => true, 'cc' => array('person1@example.com', 'person2@example.com', 'person3@example.com') ); $numSent = wireMail($to, '', $subject, $textBody, $options); There are methods to your disposal to check if you have the right WireMail-Class and if the SMTP-settings are working: $mail = wireMail(); if($mail->className != 'WireMailSmtp') { // Uups, wrong WireMail-Class: do something to inform the user and quit echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; return; } if(!$mail->testConnection()) { // Connection not working: echo "<p>Couldn't connect to the SMTP server. Please check the {$mail->className} modules config settings!</p>"; return; } A MORE ADVANCED DEBUG METHOD! You can add some debug code into a template file and call a page with it: $to = array('me@example.com'); $subject = 'Wiremail-SMTP Test ' . date('H:i:s') . ' äöü ÄÖÜ ß'; $mail = wireMail(); if($mail->className != 'WireMailSmtp') { echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; } else { $mail->from = '--INSERT YOUR SENDER ADDRESS HERE --'; // <--- !!!! $mail->to($to); $mail->subject($subject); $mail->sendSingle(true); $mail->body("Titel\n\ntext text TEXT text text\n"); $mail->bodyHTML("<h1>Titel</h1><p>text text <strong>TEXT</strong> text text</p>"); $dump = $mail->debugSend(1); } So, in short, instead of using $mail->send(), use $mail->debugSend(1) to get output on a frontend testpage. The output is PRE formatted and contains the areas: SETTINGS, RESULT, ERRORS and a complete debuglog of the server connection, like this one: Following are a ... List of all options and features testConnection () - returns true on success, false on failures sendSingle ( true | false ) - default is false sendBulk ( true | false ) - default is false, Set this to true if you have lots of recipients (50+) to ($recipients) - one emailaddress or array with multiple emailaddresses cc ($recipients) - only available with mode sendSingle, one emailaddress or array with multiple emailaddresses bcc ($recipients) - one emailaddress or array with multiple emailaddresses from = 'person@example.com' - emailaddress, can be set in module config (called Sender Emailaddress) but it can be overwritten here fromName = 'Name Surname' - optional, can be set in module config (called Sender Name) but it can be overwritten here priority (3) - 1 = Highest | 2 = High | 3 = Normal | 4 = Low | 5 = Lowest dispositionNotification () or notification () - request a Disposition Notification subject ($subject) - subject of the message body ($textBody) - use this one alone to create and send plainText emailmessages bodyHTML ($htmlBody) - use this to create a Multipart Alternative Emailmessage (containing a HTML-Part and a Plaintext-Part as fallback) addSignature ( true | false ) - the default-behave is selectable in config screen, this can be overridden here (only available if a signature is defined in the config screen) attachment ($filename, $alternativeBasename = "") - add attachment file, optionally alternative basename send () - send the message(s) and return number of successful sent messages debugSend(1) - returns and / or outputs a (pre formatted) dump that contains the areas: SETTINGS, RESULT, ERRORS and a complete debuglog of the server connection. (See above the example code under ADVANCED DEBUG METHOD for further instructions!) getResult () - returns a dump (array) with all recipients (to, cc, bcc) and settings you have selected with the message, the message subject and body, and lists of successfull addresses and failed addresses, logActivity ($logmessage) - you may log success if you want logError ($logmessage) - you may log warnings, too. - Errors are logged automaticaly useSentLog (true | false) - intended for usage with e.g. third party newsletter modules - tells the send() method to make usage of the sentLog-methods - the following three sentLog methods are hookable, e.g. if you don't want log into files you may provide your own storage, or add additional functionality here sentLogReset () - starts a new LogSession - Best usage would be interactively once when setting up a new Newsletter sentLogGet () - is called automaticly within the send() method - returns an array containing all previously used emailaddresses sentLogAdd ($emailaddress) - is called automaticly within the send() method Changelog: https://github.com/horst-n/WireMailSmtp/blob/master/CHANGELOG.md
  11. Let's say I have Fieldset Group called Tables that contains 3 x Pro Fields table. Each table is label, value where label is set via the API and is readonly (see below). If I set the field to be Closed on load, how can I set it so that if in any of the tables if value is empty instead of seeing a closed fieldset: Tables ... I get something like: Tables ... 7 missing values or Tables (7 missing values) ... (either is okay) Additional questions: I also want to hide the new row button but I think I can easily do that with CSS. Use this CSS: li#Inputfield_{myFieldName}pageText a.InputfieldTableAddRow { display: none; } How can I make the label field in the table readonly, add readonly=readonly to the settings for that column doesn't do it. Use this JS: $('input.{myFieldName}-label').attr('readonly', 'readonly').attr('onfocus', 'this.blur()').css('opacity', 0.6); How to sort the table A to Z by label Didn't realise there is a setting for this, great! Thanks. EDIT: Here's how I did it: \ProcessWire\wire()->addHookAfter('ProcessPageEdit::buildForm', function(\ProcessWire\HookEvent $event) { $object = $event->object; $form = $event->arguments('form'); $page = $object->getPage(); $page->of(false); if ($page->myField) { $toAction = 0; foreach ($page->$myField as $row) { if (!$row->value) { $toAction ++; } } if ($toAction > 0) { $form->prependMarkup('<div class="pw-container uk-container uk-container-expand"><div class="uk-alert uk-alert-danger"><span class="fa fa-exclamation-circle"></span> Check the <strong>Page text</strong> tab; ' . (int) $toAction . ' value(s) needs entering</div></div>'); } } });
  12. I may be missing something glaringly obvious here (I am admittedly tired!)… I have the text formatter TextformatterMarkdownExtra applied to a field that uses EasyMDE in the front end. If I add HTML to the field it gets putput as is. E.g. This is <strong>bold</strong>. This is bold. I thought Markdown would trip out HTML by default. Indeed, in the module settings if I submit the under the Test Markdown section I get: <p>This is &lt;strong&gt;bold&lt;/strong&gt;.</p> But on the front end it renders as: <p>This is <strong>bold</strong>.</p> Any ideas? It's not a massive issue as a client wouldn't typically even know what HTML is but thought I'd check. EDIT: I just tried another site and the other one seems to work as expected but I can't see anything different in the settings! The only difference I can see is the site that doesn't work uses 3.0.229 and the one that does uses 3.0.246. Both use the same version of TextformatterMarkdownExtra (1.8.0).
  13. Hi everyone, Like many of you, I have relied on the Pages2Pdf module in the past. It was a great tool, but unfortunately, it seems to be no longer actively maintained. With the shift to PHP 8 in most modern environments, the older version of the underlying mPDF library used in the original module has become a bottleneck, causing compatibility issues. Since I needed a working solution for a current project, I have already created a fork and updated the code to work with a newer, PHP 8 compatible version of mPDF. The Idea: Wire2Pdf I am planning to release this updated version as a new module under the name Wire2Pdf. This would distinguish it from the legacy module and allow for new features (like custom font support) without breaking older installations. What I have done in a fork so far: Code refactoring for PHP 8 compatibility. Updated the mPDF library to a recent supported version. -> https://github.com/markusthomas/Pages2Pdf Before I proceed... I wanted to check with you first: Is there still a strong interest in a maintained module based on mPDF, or have you moved to other solutions (like RockPdf)? Are there specific pain points you had with Pages2Pdf that I should address if I move forward with Wire2Pdf? If there is enough interest, I will polish the code, package it as a new module, and release it. Cheers! Markus
  14. if($user->isLoggedin() && !$input->get('profile') && !$input->get('logout')) { echo '<h2>'.__('Mein Profil').'</h2>'; echo '<p><strong>'.$user->fields[130].': </strong>' . '<span>'.$user->givenname.'</span></p>'; echo '<p><strong>'.$user->fields[131].': </strong>' . '<span>'.$user->lastname.'</span></p>'; echo '<p><strong>'.$user->fields[92].': </strong>' . '<span>'.$user->email.'</span></p>'; echo '<p><strong>'.$user->fields[171].': </strong>' . '<span>'.$user->units_balance.'</span></p>'; } I don't know why none of the values don't return anything (in the span tags). Also, the ->fields[] API is not very elegant either.
  15. <?php namespace Processwire; $contact_form = $pages->get("template=contact"); $company = $pages->get("template=company"); $form = new \FrontendForms\Form('Form'); $form->setHtml5Validation(true); // Enable HTML5 browser validation // First Name $firstname = new \FrontendForms\InputText('scf_firstname'); $firstname->setLabel($fields->get('scf_firstname')->$label); $firstname->setRule('required'); $form->add($firstname); // Last Name $lastname = new \FrontendForms\InputText('scf_lastname'); $lastname->setLabel($fields->get('scf_lastname')->$label); $lastname->setRule('required'); $form->add($lastname); // Phone $phone = new \FrontendForms\InputText('scf_phone'); $phone->setLabel($fields->get('scf_phone')->$label); $phone->setRule('required'); $form->add($phone); // Email $email = new \FrontendForms\InputText('scf_email'); $email->setLabel($fields->get('scf_email')->$label); $email->setRule('required'); $form->add($email); // SERVICES $service = new \FrontendForms\Select('scf_service'); $service->setLabel(__($fields->get('scf_service')->$label)); // Add options dynamically based on existing pages $services = wire('pages')->find('template=insurance|telephony|pension, sort=name'); // Add options dynamically based on existing pages foreach ($services as $servicePage) { $service->addOption($servicePage->title, $servicePage->id); } $form->add($service); $message = new \FrontendForms\Textarea('scf_message'); $message->setLabel($fields->get('scf_message')->$label); $message->setRule('required'); $form->add($message); $button = new \FrontendForms\Button('submit'); $button->setAttribute('value', $fields->get('label_send')->label); $button->setAttribute('class', 'btn btn-primary'); // Add the CSS class $form->add($button); if($form->isValid()){ $p = new Page(); $p->template = 'contact_inquiry'; $p->parent = wire('pages')->get('template=contact'); $p->title = $form->getValue('scf_firstname') . ' ' . $form->getValue('scf_lastname'); $p->scf_firstname = $form->getValue('scf_firstname'); $p->scf_lastname = $form->getValue('scf_lastname'); $p->scf_phone = $form->getValue('scf_phone'); $p->scf_email = $form->getValue('scf_email'); $p->scf_service = $form->getValue('scf_service'); $p->scf_message = $form->getValue('scf_message'); // Set the scf_date field to the current date and time with the correct timezone $dateTime = new \DateTime('now', new \DateTimeZone('Europe/Stockholm')); $p->scf_date = $dateTime->format('Y-m-d H:i:s'); $p->save(); // Retrieve the title of the selected legal service $selectedserviceID = $form->getValue('scf_service'); $selectedservice = wire('pages')->get($selectedserviceID); $selectedserviceTitle = $selectedservice ? $selectedservice->title : 'Not specified'; // Initialize $messageBody $messageBody = ''; $m = wireMail(); $m->to('test@gmail.com'); $m->subject("{$contact_form->scf_email_title} {$selectedserviceTitle}, {$form->getValue('scf_firstname')} {$form->getValue('scf_lastname')}"); // Set "Reply-To" address $m->header('Reply-To', $form->getValue('scf_email') . ' (' . $form->getValue('scf_firstname') . ' ' . $form->getValue('scf_lastname') . ')'); $messageBody .= "<strong>{$fields->get('scf_firstname')->label}:</strong> " . $form->getValue('scf_firstname') . "<br>"; $messageBody .= "<strong>{$fields->get('scf_lastname')->label}:</strong> " . $form->getValue('scf_lastname') . "<br>"; $messageBody .= "<strong>{$fields->get('scf_phone')->label}:</strong> " . $form->getValue('scf_phone') . "<br>"; $messageBody .= "<strong>{$fields->get('scf_email')->label}:</strong> " . $form->getValue('scf_email') . "<br><br>"; $messageBody .= "<strong>{$fields->get('scf_service')->label}:</strong> " . $selectedserviceTitle . "<br><br>"; $messageBody .= "<strong>{$fields->get('scf_message')->label}</strong><br>" . $form->getValue('scf_message') . "<br>"; $m->bodyHTML($messageBody); $m->send(); // Set up the email for the form submitter $confirmationEmail = wireMail(); $confirmationEmail->to($form->getValue('scf_email')); $confirmationEmail->subject("{$contact_form->scf_email_confirmation_title} {$selectedserviceTitle}"); $confirmationMessage = "{$contact_form->scf_email_confirmation_message}"; $confirmationEmail->bodyHTML($confirmationMessage); $confirmationEmail->send(); // Redirect to the success page wire('session')->redirect(wire('config')->urls->root . 'arendet-skickades/'); } echo $form->render(); ?> When i insert like XX into the email field there is an error Error: Exception: Invalid email address (in E:\Wamp\www\website\wire\core\WireMail.php line 162). I dont know how to validate the email adress before sending the form. Any clues?
  16. <?php namespace Processwire; $form = new \FrontendForms\Form('myForm'); $firstname = new \FrontendForms\InputText('scf_firstname'); $firstname->setLabel($fields->get('scf_firstname')->$label); $firstname->setRule('required'); $form->add($firstname); $lastname = new \FrontendForms\InputText('scf_lastname'); $lastname->setLabel($fields->get('scf_lastname')->$label); $lastname->setRule('required'); $form->add($lastname); $phone = new \FrontendForms\InputText('scf_phone'); $phone->setLabel($fields->get('scf_phone')->$label); $phone->setRule('required'); $form->add($phone); $email = new \FrontendForms\InputText('scf_email'); $email->setLabel($fields->get('scf_email')->$label); $email->setRule('required'); $form->add($email); $legalservice = new \FrontendForms\Select('scf_legalservice'); $legalservice->setLabel(__($fields->get('scf_legalservice')->$label)); // Add options dynamically based on existing pages $legalservices = wire('pages')->find('template=legal_service'); foreach ($legalservices as $service) { $legalservice->addOption($service->title, $service->id); } $form->add($legalservice); $message = new \FrontendForms\Textarea('scf_message'); $message->setLabel($fields->get('scf_message')->$label); $message->setRule('required'); $form->add($message); $button = new \FrontendForms\Button('submit'); $button->setAttribute('value', $fields->get('label_send')->label); $form->add($button); if($form->isValid()){ $p = new Page(); $p->template = 'contact_inquiry'; $p->parent = wire('pages')->get('template=contact'); $p->title = $form->getValue('scf_firstname') . ' ' . $form->getValue('scf_lastname'); $p->scf_firstname = $form->getValue('scf_firstname'); $p->scf_lastname = $form->getValue('scf_lastname'); $p->scf_phone = $form->getValue('scf_phone'); $p->scf_email = $form->getValue('scf_email'); $p->scf_legalservice = $form->getValue('scf_legalservice'); $p->scf_message = $form->getValue('scf_message'); // Set the scf_date field to the current date and time with the correct timezone $dateTime = new DateTime('now', new DateTimeZone('Europe/Stockholm')); $p->scf_date = $dateTime->format('U'); // 'U' format returns the Unix timestamp $p->save(); $m = wireMail(); $m->to('info@...'); // please change it $m->subject('Nytt ärende'); $messageBody .= "<strong>{$fields->get('scf_firstname')->label}:</strong> " . $form->getValue('scf_firstname') . "<br>"; $messageBody .= "<strong>{$fields->get('scf_lastname')->label}:</strong> " . $form->getValue('scf_lastname') . "<br>"; $messageBody .= "<strong>{$fields->get('scf_phone')->label}:</strong> " . $form->getValue('scf_phone') . "<br>"; $messageBody .= "<strong>{$fields->get('scf_email')->label}:</strong> " . $form->getValue('scf_email') . "<br>"; // Retrieve the title of the selected legal service $selectedLegalServiceID = $form->getValue('scf_legalservice'); $selectedLegalService = wire('pages')->get($selectedLegalServiceID); $selectedLegalServiceTitle = $selectedLegalService ? $selectedLegalService->title : 'Not specified'; $messageBody .= "<strong>{$fields->get('scf_legalservice')->label}:</strong> " . $selectedLegalServiceTitle . "<br>"; $messageBody .= "<strong>{$fields->get('scf_message')->label}:</strong> " . $form->getValue('scf_message') . "<br>"; $m->bodyHTML($messageBody); $m->send(); // Redirect to the success page wire('session')->redirect(wire('config')->urls->root . 'forfragan-skickades/'); } echo $form->render(); ?>
  17. Hello There PW fans and users. I Thought i share something that i came up with a while ago when i decided to adopt the teachings in this guide: MaintainableCSS This guide has made my development much easier cause i allways was stressed about having all code in one giant file and jumping around trying to keep everything organized and clear. So i decided to go with modules, as i call them, having all the CSS belonging to a specific module in one file, and also the responsive media querys that belongs to the module in the same file. Now... so far so good. Turns out that there is a 31 file limit in browsers to how many files you can load with css. And also i wanted to make less HTTP requests, so i started thinking, and came up with a simple PHP script that i run on my PW site in a hidden template and when that PHP script runs, it combines/compiles or merges the CSS module files together to one giant file that i link to in my website header. This way, there is one HTTP request for all the CSS that runs the site, minus some third party stuff. Lets look at the PHP script <?PHP /* EyeDentifys CSS File combiner. v1.0 Array of essential files - update as needed. We do this to ensure the order of how the files are combined. You can have as many CSS module files here as you want. Remember that the combined file is compiled in the order they are placed in the array. Remember to check all the paths so they reflect your setup before use. And also, the combined file is overwritten without notice when you re-combine. */ $cssModules[] = 'module_global.css'; $cssModules[] = 'module_table.css'; $cssModules[] = 'module_forms.css'; $cssModules[] = 'module_layout.css'; /* init vars */ $str = ''; $moduleCount = 0; $errorCount = 0; $listFiles = ''; /* add a string with the latest update time and date to the top of the combined file */ $dateStr = date('Y-m-d H:i:s'); $str .= '/* Combined file last updated at ' . $dateStr . ' */' . PHP_EOL; /* go through modules and concatenate them in a string var */ foreach($cssModules AS $key => $module){ /* check if the file exist */ if(file_exists('css/modules/' . $module)){ /* read file data */ $str .= file_get_contents('css/modules/' . $module); /* add module count - used for output in template */ $moduleCount++; /* add the file to list */ $listFiles[] = '[' . $module . ']'; } else { /* if the file do not exist add it to the "do not exist" list */ $listFiles[] = 'Error - file [' . $module . '] do not exist!'; /* increment error count */ $errorCount++; } } /* render the combined css */ echo('<h2>Combined CSS</h2><pre class="code-view-pre">' . $str . '</pre>'); /* list combined files */ echo('<h2>Combined files</h2>'); echo('<ul class="unstyled-list">'); foreach($listFiles AS $key => $file) { echo('<li>' . $file . '</li>'); } echo('</ul>'); echo('<p>Number of file errors <strong>' . $errorCount . '</strong> st.</p>'); /* the file name defaults */ $combinedFileName = 'css/combined_styles.css'; $backupFileName = 'css/backups/backup_styles_' . date("Y-m-d_H-i-s") . '.css'; /* backup the old combined file before updating it */ copy($combinedFileName, $backupFileName); echo('<p>Backup created to file: <strong>' . $backupFileName . '</strong></p>'); /* create update the combined css file */ file_put_contents($combinedFileName, $str); echo('<p>Combined css file: <strong>' . $combinedFileName . '</strong> updated!</p>'); echo('<p><strong>' . $moduleCount . '</strong> files combined.</p>'); ?> Like i said above, i have this in a hidden Template file that i run when logged in as ADMIN. I just refresh the page everytime i made a change and uploaded to the server so the new changes is combined into the big file and can be seen on the website. My script assumes the following directory structure: 1. This is where the script looks for the module files: templates -> css -> modules 2. This is where the script saves the combined big CSS file: templates -> css 3. This is where the script saves a backup of the current big CSS file before creating and writing over the new big file: templates -> css -> backups You need to go through the script and change the hardcoded paths to suit your needs before use. Also please try this out at some test site first so you get the hang of it. Be safe. This way of dealing with alot of CSS code has realy made my life much easier. Cause if i want to change some modules CSS i just open that file, make the changes, upload the module, and run the script and its compiled in with the other CSS in the big file. I am sure you creative fellows on the forums can make refinements to this code, but it has served me well. Hope it helps someone.
  18. I don't have strong feelings about checkmark style versus toggle style checkbox controls. It sounds like some people do. I'm fine with regular checkmark style being the default rather than the toggle style, but I divert to the designers. I don't understand the strong feelings because they both represent the same selected (1) or not selected (0) states. You posted a screenshot with "light" (left) and "dark" (right) labels, and that is not what we are doing. Those labels make it represent something else. That relates more to our dedicated toggle Inputfield, which has an entirely different appearance. In the physical world, the checkmark style represents something we would do with a pen, and the toggle style represents something we'd do with our hands on a machine. If I think of an airplane cockpit, there won't be any physical check boxes and marks. The same is true with literally any physical tool or machine we interact with. On my Android phone at least, there are no checkmark style inputs in the OS, they are all toggle style. So I'm quite used to them being one and the same as check marks, which is probably why I don't notice one way or the other. But I do prefer checkboxes when they are unlabeled and in the far-most right column of a table, like a delete checkbox, because it uses a little less space, even if a toggle style checkbox might be easier to click/tap vs. an unlabeled checkbox.
  19. @ryan thanks for doing this work! For process modules, I want to point out that you can use variables like this color: var(--text-color, #000); This will use the light/dark color from the new theme, but default to black if the variable doesn't exist and, therefore, work on the current theme also. I tend not to agree with this. The submenus have a completely different feeling than the main menu, since they are boxed and stacked vertically and allow for a much stronger marking with the background. The size of the font is also smaller and denser, and it's readability would suffer more with a lighter color. Also, unlike the main menu, the links in the submenus are not even marked with the active class, since many of them don't even represent pages, but actions. There seems to be a strong reaction against the toggles, and some good arguments. Although I would argue that, comparing to the light switch situation (referred on a blog post linked in the other thread), our toggles on and off states are unequivocally clear because of the use of muted vs strong colors. @jploch and I really like how the toggles look like in the theme, but are not insensitive to the requests. We'll discuss possible solutions with @ryan. I personally made a point in keeping the number of css vars low. I'm totally open to tweaking them, and adding a couple more, but I will definitely not add a bunch more. The idea of these variables is to allow users very easily create a different feeling to the admin, by only changing a few colors. Having few variables and making them depend, by default, on other variables, allows you to completely change all the colors with defining only 5 or 6 variables. You are correct that changing the background also changes the button text, the reason is that, like this I know for sure, that whatever colors you chose, there will be contrast between the background of the button and the text even if you don't define the (--button-color) variable yourself. For a complete change and control of the admin theme (not only colors), I would say it's better to with the original theme or AdminStyleRock and LESS. Again, this doesn't mean that we can't tweak the variables to account for cases like in your example. There's no special reason why it's --muted-color and not --muted-text-color. In our opinion, the most important information on pages list is the the name of the the pages, and the most important action is to find the page you need to work on. The action buttons are always the same, and so, it's much easier for you to find the one you want to activate, then looking for the correct page on the list. Most of the time you will even be clicking "edit", which is the first one to the right of the page name. That's a very automated process. Also, in our case, "muted" does not mean unreadable. We want the hidden pages to be as easy to find as the non hidden pages, and easier to find than the action buttons. For us, using a softer color makes it softer to the eyes that a string of words appears from nowhere when you hover the pages in the list. Again, I'm willing to tweak the name of the variables to make them clearer, and even add a couple more variables to the list, but I wouldn't be happy to add a bunch of new variables and make the system more complex.
  20. It´s me again..don't want to be annoying but I could need a little hint for my course(event) table. my actual working events template looks like this $mo = $di = $mi = $do = $fr = $sa = $mo1 = $di1 = $mi1 = $do1 = $fr1 = $sa1 = $mo2 = $di2 = $mi2 = $do2 = $fr2 = $sa2 = $moclass = $diclass = $miclass = $doclass = $frclass = $saclass = $mo1class = $di1class = $mi1class = $do1class = $fr1class = $sa1class = $mo2class = $di2class = $mi2class = $do2class = $fr2class = $sa2class = ''; foreach($page->events->sort('time') as $a) { //->sort('-time') $time = date('G',strtotime($a->time)); $day = strftime('%A', strtotime($a->date)); $datestart = date('d.m.', strtotime($a->date)); $dateend = date('d.m.', strtotime($a->dateend)); ($time > 8 && $time <= 12 && $day == 'Montag') ? $mo .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $mo .= ''; ($time > 8 && $time <= 12 && $day == 'Dienstag') ? $di .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $di .= ''; ($time > 8 && $time <= 12 && $day == 'Mittwoch') ? $mi .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $mi .= ''; ($time > 8 && $time <= 12 && $day == 'Donnerstag') ? $do .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $do .= ''; ($time > 8 && $time <= 12 && $day == 'Freitag') ? $fr .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $fr .= ''; ($time > 8 && $time <= 12 && ($day == 'Samstag' || $day == 'Sonntag')) ? $sa .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $sa .= ''; ($time > 12 && $time < 19 && $day == 'Montag') ? $mo1 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $mo1 .= ''; ($time > 12 && $time < 19 && $day == 'Dienstag') ? $di1 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $di1 .= ''; ($time > 12 && $time < 19 && $day == 'Mittwoch') ? $mi1 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $mi1 .= ''; ($time > 12 && $time < 19 && $day == 'Donnerstag') ? $do1 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $do1 .= ''; ($time > 12 && $time < 19 && $day == 'Freitag') ? $fr1 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $fr1 .= ''; ($time > 12 && $time < 19 && ($day == 'Samstag' || $day == 'Sonntag')) ? $sa1 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $sa1 .= ''; ($time >= 19 && $day == 'Montag') ? $mo2 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $mo2 .= ''; ($time >= 19 && $day == 'Dienstag') ? $di2 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $di2 .= ''; ($time >= 19 && $day == 'Mittwoch') ? $mi2 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $mi2 .= ''; ($time >= 19 && $day == 'Donnerstag') ? $do2 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $do2 .= ''; ($time >= 19 && $day == 'Freitag') ? $fr2 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $fr2 .= ''; ($time >= 19 && ($day == 'Samstag' || $day == 'Sonntag')) ? $sa2 .= "<li class='{$a->color}'><strong><u>{$a->time} - {$a->timeend}</u><br>{$a->shorty}<br>{$a->descr}</strong><br>mit {$a->teacher}<br>{$datestart}- {$dateend}<br>{$a->count} mal<br><strong>{$a->notes}</strong></li>" : $sa2 .= ''; } $content .= <<< _EVENTS <table class="events-table table-bordered width-100"><thead><th>Montag</th><th>Dienstag</th> <th>Mittwoch</th><th>Donnerstag</th><th>Freitag</th><th>Samstag/Sonntag</th></thead> <tbody><tr><td><ul>$mo</ul></td><td><ul>$di</ul></td><td><ul>$mi</ul></td><td><ul>$do</ul></td><td><ul>$fr</ul></td><td><ul>$sa</ul></td></tr> <tr><td><ul>$mo1</ul></td><td><ul>$di1</ul></td><td><ul>$mi1</ul></td><td><ul>$do1</ul></td><td><ul>$fr1</ul></td><td><ul>$sa1</ul></td></tr> <tr><td><ul>$mo2</ul></td><td><ul>$di2</ul></td><td><ul>$mi2</ul></td><td><ul>$do2</ul></td><td><ul>$fr2</ul></td><td><ul>$sa2</ul></td></tr> </tbody></table> _EVENTS; Maybe looks a bit messy with all those shorthand code My problem is that it's too "static" I would love to have it more dynamic so every event gets it's own <td> cell instead of a <li> within a cell Soo I digged literally through the whole web but couldn´t figure it out. After a little hint from a friend I thought I got it..it's drawing the table quite nice but every event get's it's own row even if both are within same time range and one is on tuesday the other on thursday..so both could be in the first row Now I think thats due to wrong sorting. The events are sorted by date (which is beginning of the event) in admin. but while iterating through the events in the template the events are unordered event with foreach($page->events->sort('date') or -date Then I figured out that the get only sorted by day (got the german format d.m.Y though) so the 3.06.2014 comes before 14.04.2014 My newer code looks like this $i = 1; $days = array('Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag/Sonntag'); $content .= "<table><thead><tr>"; foreach($days as $d) $content .= "<th>$d</th>"; $content .= "</tr></thead><tbody>"; foreach($page->events->sort('-time') as $e) { $time = date('G',strtotime($e->time)); $day = strftime('%A', strtotime($e->date)); $datestart = date('d.m.', strtotime($e->date)); $dateend = date('d.m.', strtotime($e->dateend)); if($i % 6 == 1) $content .= "<tr>"; if($time > 8 && $time <= 12) { foreach($days as $d) { if($d == $day) { $content .= "<td>{$e->date}-{$day}-{$e->time}<strong>{$e->sort}</strong></td>"; } else { $content .= "<td></td>"; } $i++; } } if($i % 6 == 1) $content .= "</tr>"; } $content .= "</tbody></table>"; It's just a little stripped, the full code got 3 of those if($time > 8 && $time <= 12) with different time ranges of course Just noticed that the sorting is not the the only reason, the events get own rows anyways but I don't know why?! Hope could explain myself properly enough. Hopefully someone could throw a little hint on this. By the way, haven't figured out why I needed to disable if("$events" != "$this->value" || $numDeleted) as mentioned to get editable events but it´s working quite nice right now so it's not really important.. UPDATE: okay, got the sorting working. changed the time fields so they save input as unix timestamp like date field so it's better sortable Still don't get more than 1 event in the same row :/
  21. @KrlosThat is strong looking to https://processwire.com/modules/seo-maestro/ The JSON Schema is not coming from that.
  22. Hi @perplexed ah ok, i thought you were using special fields (tag/text and so on) for you rimage field, then i was thinking it would be easy just to put some strong and color in the description of the image field telling there are details you don't see but don't forget to edit those images and then fill those not visible fields for eaxmple i do this kind of thing when i use @horst croppableimage3 module to remind my victims that when adding an image to this field, you don't see it working but it generates a cropped variation and you can modify the framing to your taste thus don't be mad if you don't lke the result 😄 have a nice day
  23. You mean, type them in a text area with the spaces, like in the example above? Seems like it would be a pretty complex PHP script, but possible, I guess... If you don't mind to write something closer to the html code, it would make it really easy. You could simply wrap the notes in an element by making them bold, and make each line a paragraph: EI'll take you Dfor a rGideB EOn my gaDrbage tGruckB BOh noA And then just add something like this to style it. p { position: relative; margin-top: 1.5em; } strong { position: absolute; bottom: 1em; color: red; font-weight: inherit; } Or, if you need exactly the html code from above, do a str_replace in a text formatter from "<strong>" to "<span class='chord'>" and so on...
  24. Hi @perplexed actually,in may cases thet' where the field description is very usefull and more, you could use a nice red strong to remind your user they have to fill something special thie module by @adrian will help you emphasise the part of the description you don't want your user to miss https://processwire.com/modules/dynamic-description-notes/ honestly, i don't know how far you are in your wensite dev but i would bet this is something you would regret as soon as you need one of the great image crop modules... (i can't think of one of the many xebsites i've made with pw that don't use at least one of them...) 🙂 have a nice day
  25. I can’t believe ProcessWire Weekly is still going strong! Its 10 year anniversary was actually in May last year.
×
×
  • Create New...