Jump to content
photoman355

How to set text line/character limits in templates?

Recommended Posts

I'm sure the answer is fairly simple but I was wondering if there's an easy way to define the number of lines for a textfield in a template.  I know you can set size limits for images fairly easily using $image->size(100, 100); but wondered if there was the equivalent for text?  

Share this post


Link to post
Share on other sites

Assuming you mean the Admin side then it's nice and easy, just check the Input tab of the field in question and you'll see 'Rows' :)

My advice = DOH!

Edited by alanfluff

Share this post


Link to post
Share on other sites

Greeting photoman355,

This is not built into ProcessWire by default.  However, there are a couple of nice ways to add it.

I'm using a module in my sites that counts the entered characters, and disallows more than the set number of characters.

Here are the links:

Forum discussion: http://processwire.com/talk/topic/2343-char-counter-for-texttextarea-fields/

Module page: http://modules.processwire.com/modules/textarea-counter/

In the forum discussion, you will see both the module created by boundaryfunctions, and another concept by Soma.

One of these will work for you!

Thanks,

Matthew

Share this post


Link to post
Share on other sites

I think you mean something like this:

function wordLimiter($str, $limit = 120, $endstr = '…'){
    $str = strip_tags($str); 
    if(strlen($str) <= $limit) return $str;
        
    $out = substr($str, 0, $limit);
    $pos = strrpos($out, " ");
    if ($pos>0) {
        $out = substr($out, 0, $pos);
    }
    return $out .= $endstr;
}

echo wordLimiter($page->body);
  • Like 5
  • Thanks 1

Share this post


Link to post
Share on other sites

Hmm...not as simple as I thought.  

@alanfluff Thanks I knew about the admin side limits but the problem with adding a limit to a field is that you have to create a separate field for each size of text you need. So for example if I was reusing <?=$page->body?> multiple times the text limits would have to be the same.

@MatthewSchenker I had a read of the forum, really useful module.  In this case I can't use it as it uses the same way as Alan's method to set the limit. 

@Soma This is exactly what I was after, many thanks. I noticed you wrote this as a function.  I take it this is pulled from a functions.php file much in the same way as wordpress? To save writing lots of code this makes a lot of sense.  If I wanted to apply the function to say the $page->body tag would I use a get call first or is there a better way?

Share this post


Link to post
Share on other sites

Yes helper functions like this can be included using a separate php like in the head.inc and used throughout your templates.

I extracted this function from a module I have for a project. This module has various helper function and then I load it in the templates. It's much the same as if I would include a php with functions and just personal preference.

For example:

$helpers = $modules->get("TemplateHelpers");

then use it like this where I need it.

echo $helpers->wordLimiter($page->body);

I'm not sure what you mean by applying the function to the body. I use this function to create teaser texts that are limited, and show the complete body only on the detail page.

Of course you could modify the body output, that every time you do an echo $page->body, it will run it through a function, but I'm not sure this is a good practice.

This using a hook on the formatValue of textfields would do it: (directly in template like a include, or by making it a module)

function wordLimiter(HookEvent $event){
    $field = $event->argumentsByName('field');
    if($field->name != 'body') return;
    $str = $event->return;
    $limit = 150;
    $endstr = ' …';
    $str = strip_tags($str);
    if(strlen($str) <= $limit) return;
    $out = substr($str, 0, $limit);
    $pos = strrpos($out, " ");
    if ($pos>0) {
        $out = substr($out, 0, $pos);
    }
    return $event->return = $out .= $endstr;
}

wire()->addHookAfter("FieldtypeTextarea::formatValue", null, "wordLimiter");

// now this will trigger the above hook
echo $page->body;

But it's a little cumbersome, as you can't set the limit. Also this strips tags and on HTML text you'll lose formatting. But just to show adn example what is possible.

From your post I guess you like to do something like:

echo $page->body->limit(150); // not possible

It's not possible to do this, because the $page->body, body is just a string and not an object you could add methods to it.

But something like the following would be possible using hooks.

echo $page->wordLimiter("body", 120);

You can use addHook to add a method wordLimiter to page:

function wordLimiter(HookEvent $event){
    $field = $event->arguments[0]; // first argument
    $limit = $event->arguments[1];
    $endstr = isset($event->arguments[2]) ? $event->arguments[2] : ' …';
    $page = $event->object; // the page
    $str = $page->get($field);

    $str = strip_tags($str);
    if(strlen($str) <= $limit) return;
    $out = substr($str, 0, $limit);
    $pos = strrpos($out, " ");
    if ($pos>0) {
        $out = substr($out, 0, $pos);
    }
    return $event->return = $out .= $endstr;
}

// this will add a custom method to Page object
wire()->addHook("Page::wordLimiter", null, "wordLimiter");

// now you can do this
echo $page->wordLimiter("body", 100);

// or this
echo $page->wordLimiter("summary", 100);
  • Like 10

Share this post


Link to post
Share on other sites

Fantastic info Soma, lots of code to try out.  I really like the last method using hooks, seems like the closest I'll get to $page->body->limit(150).  Will have a play around.  Many thanks for all your help on this.

Share this post


Link to post
Share on other sites

Did I dream this or is something like this now part of the core in the dev branch?

Share this post


Link to post
Share on other sites

Did I dream this or is something like this now part of the core in the dev branch?

Not really....see Ryan's mini-tut here: http://www.flamingruby.com/blog/processwire-weekly-13/#1-2

You can easily do this using CKEditor's Wordcount plugin... ;)

Edit:

Misread first post. Disregard my post.

Edited by kongondo
Because I am an idiot :-)
  • Like 1

Share this post


Link to post
Share on other sites

Not really....see Ryan's mini-tut here: http://www.flamingruby.com/blog/processwire-weekly-13/#1-2

You can easily do this using CKEditor's Wordcount plugin... ;)

I think, the others are talking about limiting the output of a field. This plugin only counts words/chars inside of CKEditor.

Did I dream this or is something like this now part of the core in the dev branch?

@Pete: where did you found this..?

Share this post


Link to post
Share on other sites

I think, the others are talking about limiting the output of a field. This plugin only counts words/chars inside of CKEditor.

Aaah, thanks. Didn't read it properly, thanks. 

Share this post


Link to post
Share on other sites

@Soma Your code seems to do the work, but does have a little issue. If you use line break or have several paragraphs, it stacks the whole text into one big mess. I have a list in one of my news stories with names on each line. This way it messes up the content quite well :/ Any workarounds for this?

Share this post


Link to post
Share on other sites

You should strip or rip the tags before using the output with a text formatter or direct in the template...

/**
 * Wordlimiter cuts a textarea only after complete words not between
 * used in admin.php for seo function and in some templates
 */
function wordLimiter($str = '', $limit = 120, $endstr = '...'){
	if($str == '') return '';
	if(strlen($str) <= $limit) return $str;
	$out = substr($str, 0, $limit);
	$pos = strrpos($out, " ");
	if ($pos>0) {
		$out = substr($out, 0, $pos);
	}
	$out .= $endstr;
	return $out;
}

/**
 * Alternative with regex for striptags function
 * used in admin.php for seo function and in some templates
 */
function ripTags($string) {
    // ----- remove HTML TAGs -----
    $string = preg_replace ('/<[^>]*>/', ' ', $string);
    // ----- remove control characters -----
    $string = str_replace("\r", '', $string);    // --- replace with empty space
    $string = str_replace("\n", ' ', $string);   // --- replace with space
    $string = str_replace("\t", ' ', $string);   // --- replace with space
    // ----- remove multiple spaces -----
    $string = trim(preg_replace('/ {2,}/', ' ', $string));
    return $string;
}

//usage in template like
$default_desc = ripTags($page->shorttext);
$default_desc_out = wordLimiter($default_desc, 160);
//or short
$default_desc = wordLimiter(ripTags($page->shorttext), 160));

regards mr-fan

Share this post


Link to post
Share on other sites

@mr-fan, I guess I'm doing something wrong here:

$default_desc = wordLimiter(ripTags($page->body), 160));

I'm trying to output the body elements of several childpages. Something I'm missing here? I got all the other code in the page too, and it runs through, yet no output.

Share this post


Link to post
Share on other sites

@mr-fan Soma's solution does already strip tags. 

@Olli like LostKobrakai wrote somas code is complete and use striptags PHP function.

Please provide more information. Have you debug mode on? Have you tried it with only wordLimiter($page->body, 160); ? and/or only ripTags($page->body); ?

regards mr-fan

Share this post


Link to post
Share on other sites

@Olli I am doing the same (with the code from post above #6)

I get my child pages

$posts = $page->children;

I loop through the posts:

foreach($posts as $p){
  $pbody = $p->wordLimiter("body", 100);
  echo($pbody);
}

& this produces the desired output.

Share this post


Link to post
Share on other sites
On 11.1.2016 at 12:08 PM, Olli said:

@Soma Your code seems to do the work, but does have a little issue. If you use line break or have several paragraphs, it stacks the whole text into one big mess. I have a list in one of my news stories with names on each line. This way it messes up the content quite well :/ Any workarounds for this?

I have searched for a solution. I would shorten the text from my blog entries. This seems to work for me. It keeps the html tags from the editor:

function truncateHtml($text, $length = 100) {
    $current_size = strlen($text);
    $diff = strlen($text);
    $remainder = $current_size - $length;
    while($diff > 0 AND $remainder > 0) {
        $pattern = "/(.*)[^<>](?=<)/s";
        $text = preg_replace($pattern, "$1", $text);
        $diff = $current_size - strlen($text);
        $current_size = strlen($text);
        $remainder = $current_size - $length;
    }
// iff $diff == 0 there are no more characters to remove
// iff $remainder == 0 there should removed no more characters
    return $text;
}

It's from here: https://stackoverflow.com/questions/38548358/cut-html-input-while-preserving-tags-with-php

Post Number 4.

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By DV-JF
      Hey all, hope you're feeling well these days!
      Short question: Under "Setup > Templates" it's possible to sort the templates by last modified. Is this possible for fields view to?
      Long explanation:
      Currently I am in the process of programming a reusable template and often have to copy several fields & templates from different PW installations into my "master version".
      Therefore it would be good to see already in the field list when the last modification has taken place.
      Stay healthy & don't forget to wash you hands - many greets!
    • By ngrmm
      I want to have filters with month names in german. I fetch them from date-fields with strftime('%B', $timestamp);
      But i'm not able to add them correctly to a wireArray()
      What's the right way to do that?
      $ms = wireArray(); $m1 = strftime('%B', 1579643232); // Januar $m2 = strftime('%B', 1583107200); // März $ms->prepend($m1); $ms->prepend($m2); foreach($ms as $name) { echo "$name "; // result: Januar M�rz }  
    • By Robin S
      This module is inspired by and similar to the Template Stubs module. The author of that module has not been active in the PW community for several years now and parts of the code for that module didn't make sense to me, so I decided to create my own module. Auto Template Stubs has only been tested with PhpStorm because that is the IDE that I use.
      Auto Template Stubs
      Automatically creates stub files for templates when fields or fieldgroups are saved.
      Stub files are useful if you are using an IDE (e.g. PhpStorm) that provides code assistance - the stub files let the IDE know what fields exist in each template and what data type each field returns. Depending on your IDE's features you get benefits such as code completion for field names as you type, type inference, inspection, documentation, etc.
      Installation
      Install the Auto Template Stubs module.
      Configuration
      You can change the class name prefix setting in the module config if you like. It's good to use a class name prefix because it reduces the chance that the class name will clash with an existing class name.
      The directory path used to store the stub files is configurable.
      There is a checkbox to manually trigger the regeneration of all stub files if needed.
      Usage
      Add a line near the top of each of your template files to tell your IDE what stub class name to associate with the $page variable within the template file. For example, with the default class name prefix you would add the following line at the top of the home.php template file:
      /** @var tpl_home $page */ Now enjoy code completion, etc, in your IDE.

      Adding data types for non-core Fieldtype modules
      The module includes the data types returned by all the core Fieldtype modules. If you want to add data types returned by one or more non-core Fieldtype modules then you can hook the AutoTemplateStubs::getReturnTypes() method. For example, in /site/ready.php:
      // Add data types for some non-core Fieldtype modules $wire->addHookAfter('AutoTemplateStubs::getReturnTypes', function(HookEvent $event) { $extra_types = [ 'FieldtypeDecimal' => 'string', 'FieldtypeLeafletMapMarker' => 'LeafletMapMarker', 'FieldtypeRepeaterMatrix' => 'RepeaterMatrixPageArray', 'FieldtypeTable' => 'TableRows', ]; $event->return = $event->return + $extra_types; }); Credits
      Inspired by and much credit to the Template Stubs module by mindplay.dk.
       
      https://github.com/Toutouwai/AutoTemplateStubs
      https://modules.processwire.com/modules/auto-template-stubs/
    • By Peter Troeger
      Hello Community 🙂
      Has anyone ever tried having multiple elements on one page that get their info with $pages->find('selector, limit=n') and tried using pagination on one of these elements without effecting the other?
      I have a slider on a page where I display content with pagination. But when I go to page two, the slider content also goes to page two, which I don't want it to do 🙂
      Any tips are greatly appreciated!
      Thanks!
      -Peter
    • By DV-JF
      Hi, 
      I'm using this kind of setup (https://processwire.com/blog/posts/language-access-control-and-more-special-permissions/#language-page-edit-permissions) in order to control the page edit permissions. Now I'm wondering if it's possible to hide the "none-ediable" language-tabs instead of striking them through.

      Many greets...
       
×
×
  • Create New...