Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/21/2020 in all areas

  1. Relative to version 3.0.164, this latest version on the master and dev branch (3.0.165) contains 16 commits with various minor fixes, improvements and optimizations, and it resolves 6 reported issues. Version 3.0.164 has been very stable, and this version should be even more so. Both the dev branch and master branch are identical at this moment. As mentioned last week, new versions of both FormBuilder and ProCache are in development, and I’ve been working on both of them quite a bit this week. I mentioned some of the updates being made in FormBuilder last week. Another new feature to mention is the addition of reCAPTCHA to the spam prevention tools. While our built in honeypot is just as effective (when setup properly), it does its work silently, behind the scenes, never visible to anyone. Whereas reCAPTCHA is hard to miss, which is a benefit for clients that want to to be able to literally see spam prevention measures in place. No doubt, it brings a certain level of comfort, and adds another level of authority to your forms. So I’m really glad to add it to our set of form tools. Rather than building it into the form “actions” I’ve instead built it as an Inputfield module (InputfieldFormBuilderRecaptcha), as this gives you a little more flexibility with regard to placement and customization. It is ready for download now in the FormBuilder board Download thread (login required). It can be used with any version of FormBuilder 0.3.9 or newer; meaning it’s ready to use now. If you download it, be sure to read the pinned reCAPTCHA thread in there for detailed instructions (it's very easy to setup). I’ve been talking about it for a long time, but it seems like it may finally be a good time to re-do the modules.processwire.com site. It all works just fine, but just needs an update, consistent with the rest of processwire.com. So we’ll likely slow the pace of core updates for 2-3 weeks to work on that, sometime between now and the end of the year. Thanks for reading and have a great weekend!
    12 points
  2. I can't say that I've been in the exact same situation, but back in the days I worked on a site that was comprised of two or three separate WordPress installations (with their own individual domains behind the scenes), one section that was powered by Craft (I believe), and probably a few other bits and pieces as well. The trick there was a separate proxy service. Sure, this was intended as a long-term solution so that's somewhat different than what you're trying to do, but if these two sites need to co-exist for a notable time, some sort of proxy solution is still the approach I'd recommend looking into. I don't have an out-of-the-box solution for this, but both nginx and Apache can handle proxying specific paths: https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ https://httpd.apache.org/docs/2.4/mod/mod_proxy.html https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html It would also be pretty simple to do this in PHP, of course — just fetch the real content with WireHttp (in ProcessWire) or wp_remote_get() (in WordPress). POST requests etc. can get a little trickier, though. That's also something you'd want to test carefully in case you decide to go on with web server level proxying ? Just for fun I did a little test using Apache mod_proxy. Probably will take this off line soon, but currently https://weekly.pw/isit/ should serve the content from isit.pw to weekly.pw ? // vhost (after enabling proxy and proxy_http apache modules) SSLProxyEngine on // .htaccess RewriteRule "^isit/(.*)$" "https://isit.pw/$1" [P] Edit: just to clarify, the solution I'm proposing here is... Separate ProcessWire and WordPress installations, with their own URLs. WP in the real domain, PW in a subdomain would likely be preferable. Installing PW in a subdirectory would result in another layer of potential complexity. Don't try to mash these up in the same directory — it's not going to work. Create new content on the ProcessWire site section (= branch) by section, and once the section is ready, proxy traffic via WP site (.htaccess, vhost, and/or PHP, depending on a few factors). Test, test, and test some more. Once everything has been proxied and no (valid) requests hit the WP site (keep track of access logs), replace the WP site with the new PW site. There are some relatively complex steps involved here, so if you're at all uncomfortable with any of it (and especially if the site is critical to the client), you should be very careful when making changes. You should also make sure that the client understands that this is a rather unconventional, and potentially risky, approach ?
    4 points
  3. Recently i have released the new version 1.0.4 of AppApi. In this version I use ProcessPageView::pageNotFound instead of the previous used ProcessPageView::execute hook. This hook is triggered later in ProcessWire's boot process, which should allow features like multi-language fields and other modules to initialize before the api tries to access their values. Let me know, if it worked for you! Besides that you can now configure the path to the Routes.php file, that is located under site/api/Routes.php per default. If you need to have it somewhere else, you can set any location (relative to ProcessWire's root directory) in the module's settings. Thanks to @thomasaull and @spoetnik for supporting me with issues and comments in the AppApi Github repository!
    2 points
  4. Release 1.0.1 is now live! It fixes the errors on ProcessWire versions below 3.0.139. Background: The module uses Inputfield::skipLabelMarkup to remove the label markup if the inputfield is configured to not display a label. This constant was introduced in ProcessWire 3.0.139. On older versions, the module now falls back to Inputfield::skipLabelHeader, which renders the label but hides it with CSS (instead of skipping the label markup completely). @aComAdi Let me know if the release isn't working for you, or if you have any more problems with the module!
    2 points
  5. There are three parts from my perspective: Filesystem => Have wordpress and processwire in separate folders URLs => You need to find a (likely .htaccess) way to move certain paths away from wordpress to processwire Migration => How do you deal with migration needs to be clarified. Can you have downtime between taking wordpress content down and pushing the pw replacement up? How much downtime is ok? All of those are solvable problems. The complexity of the last part mostly depends on how much downtime you're allowed. The less time the more automated things need to be.
    2 points
  6. This module allows you to integrate hCaptcha bot / spam protection into ProcessWire forms. hCaptcha is a great alternative to Google ReCaptcha, especially if you are in the EU and need to comply with privacy regulations. The development of this module is sponsored by schwarzdesign. The module is built as an Inputfield, allowing you to integrate it into any ProcessWire form you want. It's primarily intended for frontend forms and can be added to Form Builder forms for automatic spam protection. There's a step-by-step guide for adding the hCaptcha widget to Form Builder forms in the README, as well as instructions for API usage. Features Inputfield that displays an hCaptcha widget in ProcessWire forms. The inputfield verifies the hCaptcha response upon submission, and adds a field error if it is invalid. All hCaptcha configuration options for the widget (theme, display size etc) can be changed through the inputfield configuration, as well as programmatically. hCaptcha script options can be changed through a hook. Error messages can be translated through ProcessWire's site translations. hCaptcha secret keys and site-keys can be set for each individual inputfield or globally in your config.php. Error codes and failures are logged to help you find configuration errors. Please check the README for setup instructions. Links Github Repository and documentation InputfieldHCaptcha in the module directory Screenshots (configuration) Screenshots (hCaptcha widget)
    1 point
  7. @Zeka wrote me that this snippet does not work for him... That's because I have a custom pageClass loader in RockMigrations that triggers the init(): https://github.com/BernhardBaumrock/RockMigrations/blob/a034abce7e7fa5436756a2506d9d5f17d8a1b361/RockMigrations.module.php#L1733 So the ready() method in that case would not be triggered still, but you can easily trigger that yourself. the key is that you keep the hooks in the class itself for maintainability!
    1 point
  8. Hi @teppo Thx, it made click in my head ? I'll write about my journey and come up with suggestions at the end of the post: First try: <body> <?php if($page->is(['template' => [GemeindeGuru::tpl_teaser]])) { echo $partials->{GemeindeGuru::tpl_teaser}->body; } else { echo Wireframe::component("Header"); echo Wireframe::component("Search"); echo Wireframe::component("Slider"); } ?> </body> Nice, this already works ? 2nd try: <body> <?php switch($page->template->name) { case GemeindeGuru::tpl_teaser: echo $partials->{GemeindeGuru::tpl_teaser}->body; break; default: echo Wireframe::component("Header"); echo Wireframe::component("Search"); echo Wireframe::component("Slider"); break; } ?> </body> A lot better imho, but what if I wanted to add a custom 404 design? I'd need to duplicate the switch case: <body> <?php switch($page->template->name) { case GemeindeGuru::tpl_teaser: echo $partials->{GemeindeGuru::tpl_teaser}->body; break; case GemeindeGuru::tpl_404: echo $partials->{GemeindeGuru::tpl_404}->body; break; default: echo Wireframe::component("Header"); echo Wireframe::component("Search"); echo Wireframe::component("Slider"); break; } ?> </body> Not bad as well, but I wanted something better ? Next try: <body> <?php $body = $partials->{$page->template->name}->body; if($body) echo $body; else { echo Wireframe::component("Header"); echo Wireframe::component("Search"); echo Wireframe::component("Slider"); } ?> </body> ProcessWire\WireException Partial file not found: C:/laragon/www/kaumberg/site/templates/partials/home.php Fast-forward: I did some more testing and realized that I was actually mixing up partials and placeholders! The final (and great) version looks like this: // layouts/default.php <body> <?php if($placeholders->body) echo $placeholders->body; else { echo Wireframe::component("Header"); echo Wireframe::component("Search"); echo Wireframe::component("Slider"); } ?> </body> // views/home/body.php echo Wireframe::component("Header"); echo Wireframe::component("Search"); echo Wireframe::component("Slider"); echo Wireframe::component("News"); echo Wireframe::component("Contact"); echo Wireframe::component("Footer"); // views/teaser/body.php <div class='uk-height-viewport uk-flex uk-flex-center uk-flex-middle'> <div class='uk-text-center'> <div><img src='mylogo.svg' class='logo'></div> <div class='teaser'><?= $page->title ?></div> </div> </div> This simply means: If the view file /views/[template]/body.php exists, render it, otherwise render the default sections. That should make it really easy to create custom layouts for some templates whily still having all other assets and scripts in place (like seo, styles, analytics etc). I think I'm happy with this setup ? I realized, that I was missing the link between $placeholders->foo and /views/[template]/foo.php I read the docs again and I saw that this information IS already there ? My personal addition to this sentence: If you know where you have to look ? This illustration makes a lot of sense now. But I didn't get it quickly I have to admit. Here's my conclusion and suggestion: IMHO your docs are great explaining "how it works", but they could be improved in regards of "how I can work with it". In my experience this can make a huge difference in the experience of someone looking at it the first time. It's basically what you said earlier: Exactly that! I think if the docs where split into two sections, the first being "quickstart" and the second being what you already have, that would be brilliant. I know that what I'm asking for is a lot of work, but if we (you ?) want to build some kind of standard, it should be as easy as possible for everybody to adopt to it ? Finally I've got a question/request that you have to review from a technical point of view. As stated above, it took some time for me to grasp this easy concept: $placeholder->default loads /views/MyTemplate/default.php $placeholder->head loads /views/MyTemplate/head.php If you look at the rest of wireframe this becomes quite obvious: echo Wireframe::component("Header") --> /components/Header/default.php echo $partials->menu->top() --> /partials/menu/top.php echo $placeholders->body --> /views/[template]/body.php This really confused me when starting with wireframe! I'd expect placeholders to live in /placeholders or, the other way round, the variable to be called $views echo Wireframe::component("Header") --> /components/Header/default.php echo $partials->menu->top() --> /partials/menu/top.php echo $views->body --> /views/[template]/body.php These 3 lines would make it obvious what options you have in your layout file. But maybe that's because I've already a better understanding of what's going on, so maybe other newcomers could comment on this? What I was really missing was a guide that helps me go through a typical web project: You got a design, you got a PW installation, you installed Wireframe, what then? Now after 2 days of testing this was the way that worked great for me (so far): Set wireframe as alternate template file for all templates that should be handles via wieframe (for this walkthrough we take home.php and basic-page.php of the default site profile). Create a default layout: /layouts/default.php <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><?= $page->title ?></title> </head> <body> <h1>I am the default layout</h1> </body> </html> Open the root page of your site and the 404 page --> both should display the default layout We want a common page header and footer that is displayed on all templates. Shared markup with little to none business logic is best placed in a partial. Create 2 files: /partials/header.php <div style='border: 1px solid blue; padding: 20px;'>I am the page header</div> /partials/footer.php <div style='border: 1px solid red; padding: 20px;'>I am the page footer</div> Now you can output these partials in your layout's body: <body> <?= $partials->header ?> <h1>I am the default layout</h1> <?= $partials->footer ?> </body> What if we wanted a slider on the frontpage? And ONLY on the frontpage? That's what view files are for and they are accessed via $placeholders. (Don't you think that this is really misleading?) /views/home/slider.php <div style='padding: 20px; border: green;'>I am a SLIDER</div> And add it to the layout: <body> <?= $partials->header ?> <?= $placeholders->slider ?> <h1>I am the default layout</h1> <?= $partials->footer ?> </body> Now open both pages on the frontend and you'll see that the slider does only show up on pages having the [home] template. That magic is simply applied via file structure /views/[template]/slider.php Ok now we want to add the current local time of the user visiting the page. That will obviously need some PHP logic and as we want to separate concerns as much as possible we do NOT want to put that code into a partial. Instead, we create a component that consists of business locig (a PHP class extending \Wireframe\Component and a view file that is responsible for the output. <?php namespace Wireframe\Component; class LocalTime extends \Wireframe\Component { public function render() { return "<div> Your timezone: <strong>XXX</strong><br> Your local time: <strong>XXX</strong> </div>"; } } And add it after the footer of our layout: <body> <?= $partials->header ?> <?= $placeholders->slider ?> <h1>I am the default layout</h1> <?= $partials->footer ?> <?= Wireframe::component('LocalTime') ?> </body> Nice! We get the output at the bottom of all of our pages! We know that doing lots of output within php classes is ugly, so we refactor our setup a little and adopt another concept of wireframe: View files for components: /components/LocalTime.php <?php namespace Wireframe\Component; class LocalTime extends \Wireframe\Component { } /components/LocalTime/default.php <div> Your timezone: <strong>XXX</strong><br> Your local time: <strong>XXX</strong> </div> Of course, this is no a lot better for now, but it is a lot more future proof! Check your frontend, it should still display the same markup for your local time. Now we can add the "business logic" to our component: <?php namespace Wireframe\Component; use ProcessWire\WireData; use ProcessWire\WireHttp; class LocalTime extends \Wireframe\Component { public function __construct() { $http = new WireHttp(); $data = new WireData(); $data->setArray($http->getJSON("http://worldtimeapi.org/api/ip")); $this->timezone = $data->timezone; $this->unix = $data->unixtime; } } And update our view to output the component properties (note how they magically become available as view variables!): <div> Your timezone: <strong><?= $timezone ?></strong><br> Your local time: <strong><?= $unix ?></strong> </div> Go to your frontend and see the magic! Your timezone: Europe/Vienna Your local time: 1598007959 What, you don't want a unix timestamp? Ok... let's provide a formatter method so that you can easily output the time in different formats: <?php namespace Wireframe\Component; use ProcessWire\WireData; use ProcessWire\WireHttp; class LocalTime extends \Wireframe\Component { public function __construct() { $http = new WireHttp(); $data = new WireData(); $data->setArray($http->getJSON("http://worldtimeapi.org/api/ip")); $this->timezone = $data->timezone; $this->unix = $data->unixtime; } public function date($format = "d.m.Y H:i:s") { return date($format, $this->unix); } } @teppo now I got stuck again ? How would I display that formatted date in my view file for this component? Or would I need to provide the date format as variable for the constructor ( echo Wireframe::component('LocalTime', ['format' => 'Y-m-d']); ) PS: Regarding the last question. Controllers do expose methods to views. Is there a similar concept for components? I did implement the local time as component because this does not belong to a single template (then it would have been a controller, right?)
    1 point
  9. Do you have enabled the Imagemagick rendering engine in PW? You also may set strictly use the webp variation, also if the jpeg or png source is smaller in filesize. This is not often the case, but its possible. site/config.php: $config->webpOptions = array_merge($config->webpOptions, [ 'quality' => 84, 'useSrcExt' => false, // Use source file extension in webp filename? (file.jpg.webp rather than file.webp) 'useSrcUrlOnSize' => false, // Fallback to source file URL when webp file is larger than source? 'useSrcUrlOnFail' => true // Fallback to source file URL when webp file fails for some reason? ]);
    1 point
  10. @kongondo Aaaah I see, I always use the flyout-menu for fields, never the fields page ^^ The flyout menu only shows system fields in advanced mode, though.
    1 point
  11. These topics will give you some helpful hints: Large in terms of assets or database? Either way, it's best to make a local copy of the WordPress site and do the migration to ProcessWire locally first.
    1 point
  12. Actually you don't need this :-). Just need to use Filters -> Show System Fields :-).
    1 point
  13. The way I see it: if it's output-related, I prefer to put it into a Controller. This is the layer that handles everything that isn't needed in Admin or when loading the page outside Wireframe render context (hooks etc.) In my "ideal project" Controllers provide the backend implementation for the front-end; an API of sorts. I prefer to keep my view files as "low-logic" as possible, and everything that looks like code (external API calls, database queries, complex loops that iterate over content and convert it into some sort of list, etc.) go to Controllers instead. Controllers also provide out-of-the-box some caching features that I've found pretty handy: all Controller method return values go into run-time cache (non-persistent, for a single request), and they have built-in support for persistent caching. In the next release Controllers will also interact with the new companion module WireframeAPI. And yes, obviously one of the reasons I personally prefer Controllers over custom Page classes is that I can bundle in features that I find useful in multiple (most) projects ? Note that while Controllers are by default tied to a specific Template (TeaserController etc.) that's not a must — especially in the later versions of Wireframe this line gets blurrier (is that a word?) and in some situations a single Controller might be applicable to more than one Template. All that being said, it's true that the line between custom Page classes and Controllers can be a little blurry, and it's often a matter of preference ? For <title> tag and SEO tags (metadata) I use a Markup module. Sadly the module that we use in our projects is not publicly available (yet... @Fokke, what do you think, would you mind releasing it? ?) Assets often these depend on the layout, so I typically don't bother to convert them to a partial. Unless it's something like a GA or chatbot tag that also includes a snippet of code and an API key or something, those I prefer to split into partials for maintainability. Now, I'm not entirely sure if I really "got" your question, but there are multiple ways to do this, and I don't think any of them is really "wrong": If you have multiple layouts that share some parts, you could convert those shared parts to partials, components, or even markup modules, depending on the complexity of each of these parts. If it's a one-off thing, i.e. all templates have essentially the same layout except that the Teaser template needs to include JS library X in the head section, sometimes the easy way out is to include a template-specific if statement in a shared layout file. (Emphasis on "sometimes".) If it's something "repeatable", like an array of JavaScript file URLs, you could define it in wireframe.php, Controller class, etc. and then iterate those items and output something like script tags in the layout. ... or you could define a placeholder: // layouts/default.php <head> <title><?= $page->title ?></title> <?= $partials->head->seo ?> <?= $placeholders->head ?> </head> // views/Teaser/head.php <meta name="author" content="<?= $page->author ?>"> <script src="my-awesome-library.js"></script> Placeholders are just a way to "inject" a specific view of a template (or multiple templates) into a predefined location in the layout file. Placeholder slots can also be filled from Controller, though I've found little use for that; sometimes this might be handy if you, say, have a Markup module that should generate the placeholder content, and you already have a controller class. Or something along those lines ? In some relatively simple projects I've had a single layout file, and then placeholders for a) custom stuff in the head area, b) aside content, and c) main content (default view — technically this is a placeholder as well). This works nicely if the page layout is the same across all / most templates, and they just need to inject their own content elements into specific locations ?
    1 point
  14. This makes no sense... if($today == $start AND $today == $start) This is redundant, it is simply 2x the same check Use this: if($today == $start)
    1 point
  15. Hello @Ralph, 1. The developer tools (Inspect Element in FF) shows the font size set in your main.css file on line 1760 for screens wider than 768px. You will need to search for other media queries to set the font size for other screen sizes. See here for more information. 2. The developer tools shows your link definition in main.css on line 1107. See this reference for more information about styling links. 3. You will need to edit your "<div id="header-wrapper">" to include whatever logo image you wish. You will most like likely need to add css styles to make the logo appear as you wish. 4. The text "', 'auto'); ; ga('send', 'pageview');" appears to a remnant from a previous copy/paste. The developer tools shows this text immediately after the <body> tag. You can edit the template where the body tag is located and delete this extraneous text. 5. A google search for changing your site's favicon will give you sufficient results to accomplish this task. Hope this helps.
    1 point
  16. I had the same problem recently and discovered the bug: When there also is a normal Repeater field above the RepeaterMatrix field, the js bug occured. You could try, if this version works for you. If so, I'll create a PR
    1 point
  17. @rookie I wish you hadn't said that. I've been using Windows since 1987. Probably need a blood transfusion to get it out of my system.
    1 point
  18. Could you please show us your code for this bit? Secondly, it is not clear whether you want to store pages from one instance in another instance. If that's the case, maybe this applies to you? https://processwire.com/blog/posts/multi-instance-pw3/#pitfalls-and-considerations
    1 point
  19. Version 3.0.161 on the dev branch continues with the updates optimizing our support for the new selector operators introduced in last week's blog post for 3.0.160. Last week I was still kind of figuring it out and the code still needed some refactoring and optimization. This week several parts have been rewritten and it's been improved quite a bit. Though the end result is still very similar to what was demonstrated last week, but now it's a lot more performant and solid. One thing new this week that's also kind of fun: you can now use more than one operator in any "field=value" selector expression, at least from the API side. And it works anywhere that you might use a selector, whether querying the database or something in memory. I think the best way to explain it is with an example. Let's say that you want to find all pages with a title containing the phrase "hello world" — you'd do this using the "contains text/phrase" operator: *= $pages->find("title*=hello world"); But let's also say that if you don't find any matches, you want to fallback to find any pages that contain the words "hello" and "world" anywhere in the title, in any order. We'd use the "contains all words" operator "~=" to do that. So now you can add that operator to the existing one, and it'll fallback to it if the first operator fails to match. So we'll append the "contains all words" operator to the previous one: ~= $pages->find("title*=~=hello world"); Cool huh? But maybe we still aren't finding any matches, so we want to fallback to something even broader. So if the phrase match fails, and the words match fails, now we want to fallback to find any pages that contain the world "hello" OR "world", rather than requiring them both. For that we can use our new "contains any words" operator: ~|= $pages->find("title*=~=~|=hello world"); This example is getting a bit contrived now, but let's say that if we still haven't found a match, we want it to find any pages that have any words starting with "hello" or "world", so it would find pages with words like "helloes", "worlds", "worldwide", etc. That's a job for our new "contains any partial words" operator: ~|*= $pages->find("title*=~=~|=~|*=hello world"); Okay last one I promise—you probably wouldn't stack this many in real life, but stay with me here. Let's say the query still didn't find anything, and as a final fallback, we want it to find any words LIKE "hello" or "world", so that those terms can match anywhere in words, enabling us to find pages with words like in the previous example, but also words like "phellogen", "othello", "underworld", "otherworldly", etc., and that's a job for our new "contains any words like" operator: ~|%= $pages->find("title*=~=~|=~|*=~|%=hello world"); So that looks like a pretty complex operator there, but as you've seen by following the example, it's just these 5 appended operators to each other: *= Contains phrase ~= Contains all whole words ~|= Contains any whole words ~|*= Contains any partial words ~|%= Contains any words like I think a more likely scenario in a site search is that you might stack two operators, such as the *= followed by the ~|*=, or whatever combination suits your need. By the way, you can do this with any operators, not just the text searching ones. But if you didn't read the blog post last week, also be sure to check out the other new operators in addition to those above: *+=, **=, **+=, ~*=, ~+=, ~~=, ~%=, #=. I think these new operators help out quite a bit with ProcessWire's text searching abilities. But there's one thing that's kind of a common need in search engines that's not easily solved, and that's the handling of singular vs. plural. At least, that's a common issue when it comes to English (I'm assuming so for other languages, but not positive?) MySQL fulltext indexes can't differentiate between singular and plural versions of words, so they index and match them independently as completely different words. This can be unexpected as clients might type in "goose" and expect it's also going to match pages with "geese". I've already got something in the works for this, so stay tuned. Thanks for reading and hope you have a great weekend!
    1 point
  20. Disclaimer: please note that this is how I am doing it, it may or may not suit you, so take it with a grain of salt. Also, I apologize for not obeying ProcessWire's code style, I'm just too old and it feels alien to me. Thing I'm trying to get: not having to input the 'Custom Editor CSS File ...' and 'Custom Editor JS Styles Set ....' for each of the fields using CKEditor. Yeah, I know, call me lazy or sloppy or whatever, it is what it is ? . having the front end styles in the editor container, so the one editing the page would be able to eyeball the styling of the content while stayin in the editor For the first objective I tried to find a way in the CKEditor configuration options, like config.js, or at least a single point to set my options. In the end, what worked for me was hooking the Inputfield in ready.php: if (strpos($_SERVER['REQUEST_URI'], $config->urls->admin) !== 0) { // things I do to frontend pages, believe me, you don't want to know :D } else { $wire->addHookBefore('InputfieldWrapper::renderInputfield', function($event) { // process further if it is an InputfieldCKEditor if (strpos($event->arguments(0)->className(), 'InputfieldCKEditor') === 0) { // store the Inputfield $inputfield = $event->arguments(0); // my custom CKEditor options $my_settings = [ 'contentsCss' => '/site/assets/css/cke.css', 'contentsInlineCss' => '/site/assets/css/cke_inline.css', 'stylesSet' => 'mystyles:/site/modules/InputfieldCKEditor/mystyles.js', 'extraAllowedContent' => '*[id](*); audio[src,controls,preload]; source[src,type]; button[title]; script; i[data-feather]; svg[xmlns,height,width]; path[d,fill,stroke]', ]; // for each option, check if it's empty and if it is set it to the custom value foreach ($my_settings as $key => $value) { if (empty($inputfield->get($key))) { $inputfield->set($key, $value); } } // get the changes into $event $event->arguments(0, $inputfield); } }); } Now, my CSS files are generated by Sass in the /site/assets/css/ directory, because of the second objective. Thus, I'm including the frontend CSS in three places: the two custom CSS files used by CKeditor in regular/inline mode and defined above ('contentsCss' and 'contentsInlineCss' options), and my custom CSS file used by admin.php. The regular mode CSS files contains: // cke.sass - Sass syntax @import "main" where main.sass is my frontend Sass file (I have a real talent for names, I know). So it includes all the frontend styles in the regular CKEditor iframe. The inline mode CSS file contains: // cke_inline.sass .cke_editable_inline @import "main" This way the frontend styles are applied only to elements inside the CKEditor inline container. I know I'm tying myself to the CKEditor markup, but as you may have noticed by now, I'm quite eager to sell myself in slavery for a bit of convenience ? . The admin styles are built the same, changing only the container class and adding some styles to increase readability: // admin.sass /* force a min width for CKEditor combo, so I can read the text */ .cke_combopanel min-height: 21rem min-width: 25rem > iframe height: 100% !important .cke @import "main" The resulting /site/assets/css/admin.css file is loaded by /site/templates/admin.php by adding $config->styles->add($config->urls->assets.'css/admin.css'); before the require($config->paths->adminTemplates . 'controller.php'); line. Lo and behold, Bulma styles available in the editor toolbar and container (there's a short clip attached). Well, this should be it. I hope it helps someone. If you know a better way to do this or if you notice a mistake/omission, by all means, let me know. Thank you for following me until now - here's the medal you rightly deserve: ? LATER EDIT: sorry about the video size, I swear it's just a little 578x472px video. ckeditor-2020-04-10-161245.mp4
    1 point
  21. Since some others and me have been run into problems with FieldtypeFloat. I want to start a discussion with the purpose to get a consistent FieldtypeFloat and/or to create a new Fieldtype maybe called FieldtypeDecimal to store exact values maybe for currencies. First I will assume some known problems. precision Values of Type Float are stored in most of the Mysql Installations with a precision of 6 by default. PW FieldtypeFloat uses Type float() in the Mysql Database This could cause some problems. For easy understanding look at this table. +---------------+----------------+--------------------------------------------------+ | input | float() | decimal(10,2) | +---------------+----------------+--------------------------------------------------+ | 1234.56 | 1234.56 | 1234.56 | +---------------+----------------+--------------------------------------------------+ | 123456.78 | 123457 | 123456.78 | +---------------+----------------+--------------------------------------------------+ | 12345678 | 12345600 | 12345678.00 | +---------------+----------------+--------------------------------------------------+ | 1.23456789 | 1.23457 | 1.23 | +---------------+----------------+--------------------------------------------------+ | 12345678912345| 12345600000000 | ERROR SQLSTATE[22003]: Numeric value out of range| +---------------+----------------+--------------------------------------------------+ As an example in Apeisas Shoppingcart Module exists a field sc_price of type float(). This field allows a maximum value of 9999.99 Euro Dollar or whatever. Don't use it to sell cars like Ferrari. Try to store the input values of the preceding table in a PW Field of Type Float in your surrounding and look what you get after saving. Threads treating the same problem https://processwire.com/talk/topic/3888-float-field-rounding-problem/ https://processwire.com/talk/topic/86-float-field-rounding rounding Mysql will round anyway the float value to precision. So it is not necessary to round the value in php before storing. To store exact Values it is better to use Type decimal(M,D) where M is the lenght and D the number of digits. Thread treating the same problem https://processwire.com/talk/topic/86-float-field-rounding format We had already some discussion about local settings, storing and output of PHP-Values of Type (float). And Ryan did some Adjustments with number_format. But I don't trust completely, thats why I am using Textfields to store numbers. Would be nice to have a consistent Fieldtype working in different local-settings. Thread treating the same problem https://processwire.com/talk/topic/4123-decimal-point-changed-to-in-base-of-setlocale/ https://processwire.com/talk/topic/86-float-field-rounding What is a float (floating point value), what is decimal? A float is an approximate value and exactly like this it is stored in Mysql. For more understanding two examples. 1. example CREATE TABLE `test` ( `test_float` float(10,2) NOT NULL, `test_decimal` decimal(10,2) NOT NULL ); INSERT INTO `test` (`test_float`, `test_decimal`) VALUES (5.43, 5.43); SELECT (test_float * 1.0000000) AS f, (test_decimal * 1.0000000) AS d FROM test; This will result the following: f = 5.4299998 and d = 5.430000000 source: http://netzgewe.be/2012/03/mysql-und-waehrungsbetraege-float-vs-decimal/ (german) 2. example mysql> create table numbers (a decimal(10,2), b float); mysql> insert into numbers values (100, 100); mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G *************************** 1. row *************************** @a := (a/3): 33.333333333 @b := (b/3): 33.333333333333 @a + @a + @a: 99.999999999000000000000000000000 @b + @b + @b: 100 source: http://stackoverflow.com/questions/5150274/difference-between-float-and-decimal-data-type INFO & LEARNING http://stackoverflow.com/questions/5150274/difference-between-float-and-decimal-data-type http://stackoverflow.com/questions/4520620/float-precision-problem-in-mysql http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html INTENTION The intention of this thread is to discuss good solutions for a consistent working FieldtypeFloat which makes clear to Everybody what it is via description. Furthermore to build a new Fieldtype with setting options of total lenght and decimal places. NOTES Please use this thread rather for development than as a help forum. BTW I am not an expert in Mysql PHP or whatever. Maybe there are some guys in the forum which could put the real good stuff here. Thanks a lot and lets go.
    1 point
  22. Hi ... Here you should find a lot about the translations https://processwire.com/api/multi-language-support/code-i18n/ I do not know if this is the best solution, but it works for me ... Thanks to this, I do not have to search for translations in all of the template's peaks ... So I create a simple file responsible for all translations _translate.php Include this file inside _init.php include_once('./_func.php'); include_once('./_translate.php'); And define in the table as below <?php namespace ProcessWire; // Translate Strings page()->ts = [ // Language => locale / code prefx 'locale' => _x('en_US', 'HTML locale code'), 'lang_code' => _x('en', 'HTML language code'), // Main Page ( main.php ) 'site_name' => __('Your Site Name'), 'logo_alt' => __('Show My Awesome Logo'), // Archives Page 's_archives' => __('Select The Archives'), 'date' => __('Date'), ]; Then you can call globally using page() <h1><?=page()->ts['site_name'];?></h1> And there is a pro option Functional Fields: https://processwire.com/blog/posts/functional-fields/ But I can not say too much about it because I have not tested it but it looks interesting ?
    1 point
×
×
  • Create New...