Tinymce images auto-wrapped in <p> tag. CSS ways around or text editor hacks
Asked Answered
W

9

12

Hiya,
I have run into this problem many times now using drupal or wordpress where my tinymce config files are a bit too cleverly abstracted.

The problem is that tinymce auto-wraps my <img> tags in <p> tags. If there is a way around this in either Wordpress or Drupal, that would be awesome.

My problem exists when I want to do something like this

<style>
    img {
        float: left;
    }
    p {
        float: right;
        margin-right: 20px;
        width: 400px;
    }
 </style>

and I want my code to look like this

<img src="some_png.png" />
<p> Imagine a lot of lipsum text.</p>

but tinymce does this

<p><img src="crap_im_wrapped_in_a_paragraph.png" /></p>
<p> Imagine a lot of lipsum text.</p>

I'm trying to float an image to the left of a paragraph with a set width, without having width restraints on the image itself.
in this case the image's parent then gets a width and a float right. That is not what I want.

It is very possible that there is an easy clever fix for this but I still have not found one. I would prefer not hacking my config files if I don't have to.

1 caveat...
The only reason this problem exists is because I want clients to be able to easily do their own editing so I won't just have them wrap the image in a <div> instead of a <p>. That seems to me unintuitive for my clients who are the actual users of the wysiwyg

Previous Solution
I have been using a regex to remove the paragraph tags but it is always somehow problematic. I end up adding more images somewhere else then i have to keep tuning my regex to ignore them. 502 errors abound!

my question(s) is(are)
What can I to in my CSS to make the image wrapped in the paragraph do what I want it to do?
and if i can't
What drupal or wordpress specific can I do to make that paragraph disappear?

-- Edit -- the solution needs to be compatible with IE7+ and modern browsers. :P

Thanks!
aaron

Woodland answered 28/4, 2011 at 14:8 Comment(2)
I know about tinyMCE.init.forced_root_block but I don't know how to implement it or if it will even work.Woodland
crap, here's the link tinymce.moxiecode.com/wiki.php/Configuration:forced_root_blockWoodland
M
6

If you don't want it to wrap image tags, look in the Tinymce source for a function called "isBlock". There is a regular expression white list test that determines whether or not an element is a block element. If you need image tags to be treated as block elements then add "IMG" to the list of node names it looks for. I just had to do this myself, am still looking for negative side effects right now but it does solve the immediate problem at hand.

EDIT: That was more or less a temporary solution, if you just need to stop the root level block wrapping of image tags, there's a function called "forceRoots" where you'll actually want to perform your image tag check. I did it by modifying this line of code:

if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8)) {

to look like this:

if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8) && nx.nodeName.toLowerCase() != "img") {

This solves the problem quite well for me.

Medicament answered 1/6, 2011 at 19:42 Comment(2)
I am lucky enough to not have to use TinyMCE anymore so I will unfortunately probably never be able to test these solutions. Answer goes to most votes.Woodland
To apply this change in tinyMCE4, look for blockElementsMap = createLookupTable('...') and add img to the list of block elements. I haven't tested for side effects!Intendant
R
8

You call tinyMCE with tinyMCE.init function, don't you?

So add this string to it:

forced_root_block : false,

Also you can change tiny_mce_src.js. Find

forced_root_block : 'p',

and change it to

forced_root_block : false,

P.S. Don't forger to clear the cache.

Ripley answered 11/7, 2011 at 8:36 Comment(1)
The TinyMCE Docs say: "If you set this option to false it will never produce P tags on enter or automatically it will instead produce BR elements and Shift+Enter will produce a P. Note that not using P elements as root block can severly cripple the functionality of the editor." Maybe this is ok for some people, but use at your own risk!Intendant
M
6

If you don't want it to wrap image tags, look in the Tinymce source for a function called "isBlock". There is a regular expression white list test that determines whether or not an element is a block element. If you need image tags to be treated as block elements then add "IMG" to the list of node names it looks for. I just had to do this myself, am still looking for negative side effects right now but it does solve the immediate problem at hand.

EDIT: That was more or less a temporary solution, if you just need to stop the root level block wrapping of image tags, there's a function called "forceRoots" where you'll actually want to perform your image tag check. I did it by modifying this line of code:

if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8)) {

to look like this:

if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8) && nx.nodeName.toLowerCase() != "img") {

This solves the problem quite well for me.

Medicament answered 1/6, 2011 at 19:42 Comment(2)
I am lucky enough to not have to use TinyMCE anymore so I will unfortunately probably never be able to test these solutions. Answer goes to most votes.Woodland
To apply this change in tinyMCE4, look for blockElementsMap = createLookupTable('...') and add img to the list of block elements. I haven't tested for side effects!Intendant
S
3

If we're talking about a WordPress site, there's an annoying filter that will automatically wrap some elements within the content with a <p> tag called wpautop. It's actually handled by wordpress at runtime and not by TinyMCE.

Add this to the top of your template or functions.php file:

<?php remove_filter('the_content', 'wpautop'); ?>

source:
http://wordpress.org/support/topic/stop-wordpress-from-adding-p-tags-and-removing-line-break

Subject answered 9/8, 2011 at 8:48 Comment(0)
N
2

In Drupal, one sort of "klugey" way of doing this would be to use hook_nodeapi() or the d7 equivalent(s) for displaying nodes, and using a regular expression to replace p-wrapped images occurring at the beginning of the field. You would have to inform your client that they wouldn't look right when editing, but that on display, they would appear properly.

If you're looking for a css option:

In css2 you have the :first-child selector, and in css3 there is also the :only-child selector. p:first-child img could be used with negative margins to offset margins you've declared for p elements. A downside would be that this would also impose the same negative margins on any images the client might put in a first paragraph. css3 might not be supported in all the browsers you aim to cover, but if you can use it - you could use the :only-child selector for images which are the sole children of p elements, offsetting the parent p's margins with negative margins.

Negatron answered 28/4, 2011 at 16:44 Comment(2)
Like I noted above, I have used the old regexp trick before. That is exactly what I am trying to avoid. I thought the :first-child selector wasn't as supported as it is. This seems like it will even work with IE7. The problem is still that it is very possible that I won't be working with the first-child and I am not willing to use CSS3 selectors yet. +1 though, thanksWoodland
I don't blame you for wanting to avoid the regex hack. My guess is that probably :first-child will be good enough for most of your site visitors ... though it does have drawbacks for images contained in the first paragraph when there is text present there. Good luck!Negatron
T
2

If Javascript is an option, then you can use jQuery to reparent the img to be a sibling of the p. Something like this (untested)

$("p > img").each(function () {
  var $this = $(this);
  var $p= $this.parent();
  $p.before($this);
});

Add logic to only the paragraphs/images you really need.

Ugly, yes, but a viable solution as a last resort.

Tristatristam answered 29/4, 2011 at 13:5 Comment(2)
i would make that last line $p.before($this).remove(); :OWoodland
Yeah, in your case that may be advisable. I would not do it in that function, though. A more general solution would be separate calls to remove all empty paragraphs and all paragraphs consisting solely of &nbsp;. Both of those happen with TinyMCE fairly often.Tristatristam
P
2

Add this line:

theme_advanced_blockformats : "p,div,h1,h2,h3,h4,h5,h6,blockquote,dt,dd,code,samp"

When you want to insert a img select div:

<div>
    <img src="my_img.jpg>
</div>

No need to modify anything with css.

Pattern answered 16/3, 2012 at 19:48 Comment(0)
V
2

TinyMCE 4 wraps everything in block elements. The default wrapper is P. Click on the image and choose another wrapping element like DIV. To add DIV to the menu add this to functions.php:

function make_mce_awesome( $init ) {
  $init['block_formats'] = "Paragraph=p; Heading 1=h1; Heading 3=h3; Heading 2=h2; Preformatted=pre; Media=div";
return $init;
}

add_filter('tiny_mce_before_init', __NAMESPACE__ . "\\make_mce_awesome");

DIV wrapper around image

Verlaverlee answered 14/7, 2015 at 8:34 Comment(0)
I
2

There is option "valid_children" https://www.tiny.cloud/docs/configure/content-filtering/#valid_children. It controls which elements you disallow (-) or allow (+) img tag to be wrapped in.

This example is for - not letting img tag to be child of p and h1-4 - letting img tag to be child of div and span

tinymce.init({
valid_children : '-p[img],h1[img],h2[img],h3[img],h4[img],+div[img],span[img]'
});
Inculcate answered 13/5, 2019 at 15:23 Comment(0)
B
1

I fear this is not possible due to the fact that img is an inline element. Tinymce wraps everything a user enters into block elements (divs or p-tags), but img is not a block element.

Betsybetta answered 28/4, 2011 at 14:52 Comment(4)
I've read it before and this other question (#2403261) seems to imply that img tags are inline or block elements. But behave more like inline elements. So tinymce would not be correct to wrap the image in all cases. Just most cases.Woodland
i think it should be possible to define how tinymce treats img-tags. it might work to disable forced_root_blockBetsybetta
as you can see from my comment above, I am aware of forced_root_block but don't know how to implement it in Wordpress or Drupal. Do you know how?Woodland
yes, have a look at this tutorial on how to set the tinymce init params in wordpress: lucidgreen.net/webbybooth/?p=11Betsybetta

© 2022 - 2024 — McMap. All rights reserved.