Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic PDF height using DOMPDF engine #157

Open
alexmigf opened this issue Mar 12, 2021 · 21 comments
Open

Dynamic PDF height using DOMPDF engine #157

alexmigf opened this issue Mar 12, 2021 · 21 comments
Assignees

Comments

@alexmigf
Copy link
Member

alexmigf commented Mar 12, 2021

Currently in our setup is not very easy to get the DOMPDF body height easily. Normally we provide a custom code snippet, like in here, but it's not very efficient. This is crucial for situations when customers want to print documents in a roll instead of a fixed paper size.

Slack discussion: https://wpovernight.slack.com/archives/C0121KYKGN6/p1615436120016500

DOMPDF issue suggested by @YordanSoares : dompdf/dompdf#1524

@alexmigf alexmigf self-assigned this Mar 12, 2021
@alexmigf
Copy link
Member Author

@Spreeuw maybe we should create a setting for this?

@Spreeuw
Copy link
Contributor

Spreeuw commented Mar 16, 2021

Not sure, it's a bit of an exotic setting. I would first check wether it would be possible to do this with a code snippet (and if not, what hooks would be required to be able to do that). We could always move it to a setting later.

@alexmigf
Copy link
Member Author

alexmigf commented Mar 16, 2021

Seems to work:

Captura de ecrã de 2021-03-16 14-32-01

Captura de ecrã de 2021-03-16 14-44-42

@Spreeuw
Copy link
Contributor

Spreeuw commented Mar 16, 2021

Can you share your code snippet?

alexmigf added a commit that referenced this issue Mar 16, 2021
@alexmigf
Copy link
Member Author

See here 897cc05

@Spreeuw
Copy link
Contributor

Spreeuw commented Mar 16, 2021

Apologies if my previous message was unclear: I'd like to see a separate code snippet first before we implement this into the plugin itself (for example using wpo_wcpdf_before_dompdf_render, though I'm not sure if that's possible?

@alexmigf
Copy link
Member Author

alexmigf commented Mar 16, 2021

Sorry, it's an hook, I will need to test.

@alexmigf
Copy link
Member Author

I believe is not possible because I need to access the $options to instantiate Dompdf again, but we could add a filter before that passing the variable and it should work. Let me know your opinion.

@Spreeuw
Copy link
Contributor

Spreeuw commented Mar 16, 2021

You can do:

$options = $dompdf->getOptions();

you may even be able to do:

$_dompdf = clone $dompdf;
// do your calculations using $_dompdf
unset($_dompdf);
$dompdf->setPaper( /* your height */ );

But overwriting the object is more efficient in terms of memory.

I think you should pick a less generic name for the global.

@alexmigf
Copy link
Member Author

alexmigf commented Mar 16, 2021

Working with this:

add_filter( 'wpo_wcpdf_before_dompdf_render', function( $dompdf, $html )
{
	$_dompdf                   = clone $dompdf;
	unset( $dompdf );
	$_dompdf_options           = $_dompdf->getOptions();
	$_dompdf_paper_size        = $_dompdf->getPaperSize();
	$_dompdf_paper_orientation = $_dompdf->getPaperOrientation();

	$GLOBALS['wpo_wcpdf_dompdf_body_height'] = 0;
	$_dompdf->setCallbacks(
		array(
			'myCallbacks' => array(
				'event' => 'end_frame',
				'f'     => function ( $infos ) {
					$frame = $infos["frame"];
					if ( strtolower( $frame->get_node()->nodeName ) === "body" ) {
						$padding_box                              = $frame->get_padding_box();
						$GLOBALS['wpo_wcpdf_dompdf_body_height'] += $padding_box['h'];
					}
				},
			)
		)
	);

	$_dompdf->loadHtml( $html );
	$_dompdf->render();
	unset( $_dompdf );

	if( ! empty( $_dompdf_paper_size  ) ) {
		$_dompdf_paper_size[3] = $GLOBALS['wpo_wcpdf_dompdf_body_height'] + 150;
	}

	$dompdf = new \Dompdf\Dompdf( $_dompdf_options  );
	$dompdf->loadHtml( $html );
	$dompdf->setPaper( $_dompdf_paper_size, $_dompdf_paper_orientation );

	return $dompdf;
}, 10, 2 );

@YordanSoares
Copy link
Contributor

@alexmigf I tested the code with a long list of products and works like a charm!

@alexmigf
Copy link
Member Author

This works too:

add_filter( 'wpo_wcpdf_before_dompdf_render', function( $_dompdf, $html )
{
	$_dompdf_options           = $_dompdf->getOptions();
	$_dompdf_paper_size        = $_dompdf->getPaperSize();
	$_dompdf_paper_orientation = $_dompdf->getPaperOrientation();

	$GLOBALS['wpo_wcpdf_dompdf_body_height'] = 0;
	$_dompdf->setCallbacks(
		array(
			'myCallbacks' => array(
				'event' => 'end_frame',
				'f'     => function ( $infos ) {
					$frame = $infos["frame"];
					if ( strtolower( $frame->get_node()->nodeName ) === "body" ) {
						$padding_box                              = $frame->get_padding_box();
						$GLOBALS['wpo_wcpdf_dompdf_body_height'] += $padding_box['h'];
					}
				},
			)
		)
	);

	$_dompdf->loadHtml( $html );
	$_dompdf->render();
	unset( $_dompdf );

	if( ! empty( $_dompdf_paper_size  ) ) {
		$_dompdf_paper_size[3] = $GLOBALS['wpo_wcpdf_dompdf_body_height'] + 150;
	}

	$dompdf = new \Dompdf\Dompdf( $_dompdf_options );
	$dompdf->loadHtml( $html );
	$dompdf->setPaper( $_dompdf_paper_size, $_dompdf_paper_orientation );

	return $dompdf;
}, 10, 2 );

@YordanSoares
Copy link
Contributor

@alexmigf I tested your previous code and also works 👍

@alexmigf
Copy link
Member Author

alexmigf commented Mar 17, 2021

This should do the trick for 80mm thermal printer rolls:

add_filter( 'wpo_wcpdf_paper_format', function( $paper_format, $document_type) {
	// change the values below
    $width = 80; //mm!
    $height = 115; //mm!
 
    //convert mm to points
    $paper_format = array( 0, 0, ($width/25.4) * 72, ($height/25.4) * 72 );
 
    return $paper_format;
}, 10, 2 );

add_filter( 'wpo_wcpdf_before_dompdf_render', function( $_dompdf, $html )
{
	$_dompdf_options           = $_dompdf->getOptions();
	$_dompdf_paper_size        = $_dompdf->getPaperSize();
	$_dompdf_paper_orientation = $_dompdf->getPaperOrientation();

	$GLOBALS['wpo_wcpdf_dompdf_body_height'] = 0;
	$_dompdf->setCallbacks(
		array(
			'myCallbacks' => array(
				'event' => 'end_frame',
				'f'     => function ( $infos ) {
					$frame = $infos["frame"];
					if ( strtolower( $frame->get_node()->nodeName ) === "body" ) {
						$padding_box                              = $frame->get_padding_box();
						$GLOBALS['wpo_wcpdf_dompdf_body_height'] += $padding_box['h'];
					}
				},
			)
		)
	);

	$_dompdf->loadHtml( $html );
	$_dompdf->render();
	unset( $_dompdf );

	if( ! empty( $_dompdf_paper_size  ) ) {
		$_dompdf_paper_size[3] = $GLOBALS['wpo_wcpdf_dompdf_body_height'] + 150; // if too many space at the bottom, replace this 150 value with a lower one
	}

	$dompdf = new \Dompdf\Dompdf( $_dompdf_options );
	$dompdf->loadHtml( $html );
	$dompdf->setPaper( $_dompdf_paper_size, $_dompdf_paper_orientation );

	return $dompdf;
}, 10, 2 );

Could require additional custom CSS styles.

@alexmigf
Copy link
Member Author

alexmigf commented Oct 3, 2022

The code above is now triggering this error:

Fatal error: Cannot use object of type Dompdf\FrameDecorator\Text as array

Needs to be updated to this:

add_filter( 'wpo_wcpdf_paper_format', function( $paper_format, $document_type) {
	// change the values below
    $width = 80; //mm!
    $height = 115; //mm!
 
    //convert mm to points
    $paper_format = array( 0, 0, ($width/25.4) * 72, ($height/25.4) * 72 );
 
    return $paper_format;
}, 10, 2 );

add_filter( 'wpo_wcpdf_before_dompdf_render', function( $_dompdf, $html )
{
	$_dompdf_options           = $_dompdf->getOptions();
	$_dompdf_paper_size        = $_dompdf->getPaperSize();
	$_dompdf_paper_orientation = $_dompdf->getPaperOrientation();

	$GLOBALS['wpo_wcpdf_dompdf_body_height'] = 0;
	$_dompdf->setCallbacks(
		array(
			'myCallbacks' => array(
				'event' => 'end_frame',
				'f'     => function ( \Dompdf\Frame $frame ) {
					if ( strtolower( $frame->get_node()->nodeName ) === "body" ) {
						$padding_box                              = $frame->get_padding_box();
						$GLOBALS['wpo_wcpdf_dompdf_body_height'] += $padding_box['h'];
					}
				},
			)
		)
	);

	$_dompdf->loadHtml( $html );
	$_dompdf->render();
	unset( $_dompdf );

	if( ! empty( $_dompdf_paper_size  ) ) {
		$_dompdf_paper_size[3] = $GLOBALS['wpo_wcpdf_dompdf_body_height'] + 150; // if too many space at the bottom, replace this 150 value with a lower one
	}

	$dompdf = new \Dompdf\Dompdf( $_dompdf_options );
	$dompdf->loadHtml( $html );
	$dompdf->setPaper( $_dompdf_paper_size, $_dompdf_paper_orientation );

	return $dompdf;
}, 10, 2 );

@TRIXServer
Copy link

TRIXServer commented Nov 16, 2022

The code above is now triggering this error:

Fatal error: Cannot use object of type Dompdf\FrameDecorator\Text as array

Needs to be updated to this: [Code snippet]

This solution work for me. I have 80mm thermal printers.
Thank you.

@Pratik67796
Copy link

@alexmigf How can we use this add_filter function in Laravel controller ?

@DJKAMY0
Copy link

DJKAMY0 commented Aug 14, 2023

image

image

How do I get rid of the margins on the size so that the text appears clean? please help, Thanks in advance

@alexmigf
Copy link
Member Author

alexmigf commented Aug 14, 2023

@Pratik67796

How can we use this add_filter function in Laravel controller ?

I don't think you can, it's a WordPress thing, unless you use something like this. Also, this is a filter from our own plugin, which runs only in WordPress with WooCommerce.

@alexmigf
Copy link
Member Author

@DJKAMY0

You need to apply custom CSS. See this documentation page: https://docs.wpovernight.com/woocommerce-pdf-invoices-packing-slips/using-custom-styles/

@alexmigf alexmigf changed the title Test how to get height from DOMPDF Dynamic PDF height using DOMPDF engine Aug 16, 2023
@dpeyou dpeyou unpinned this issue Jan 1, 2024
@alexmigf alexmigf pinned this issue Jan 5, 2024
@alexmigf
Copy link
Member Author

Full code with document type restriction and custom CSS styles:

add_filter( 'wpo_wcpdf_paper_format', function( $paper_format, $document_type, $document ) {
	if ( 'receipt' === $document_type ) {
		// change the values below
		$width  = 80;  //mm!
		$height = 115; //mm!
	
		// convert mm to points
		$paper_format = array( 0, 0, ( $width / 25.4 ) * 72, ( $height / 25.4 ) * 72 );
	}
 
	return $paper_format;
}, 10, 3 );

add_filter( 'wpo_wcpdf_before_dompdf_render', function( $_dompdf, $html, $options, $document ) {
	if ( 'receipt' === $document->get_type() ) {
		$_dompdf_options           = $_dompdf->getOptions();
		$_dompdf_paper_size        = $_dompdf->getPaperSize();
		$_dompdf_paper_orientation = $_dompdf->getPaperOrientation();
		
		

		$GLOBALS['wpo_wcpdf_dompdf_body_height'] = 0;
		
		$_dompdf->setCallbacks(
			array(
				'myCallbacks' => array(
					'event' => 'end_frame',
					'f'     => function ( \Dompdf\Frame $frame ) {
						if ( 'body' === strtolower( $frame->get_node()->nodeName ) ) {
							$padding_box                              = $frame->get_padding_box();
							$GLOBALS['wpo_wcpdf_dompdf_body_height'] += $padding_box['h'];
						}
					},
				)
			)
		);

		$_dompdf->loadHtml( $html );
		$_dompdf->render();
		unset( $_dompdf );

		if ( ! empty( $_dompdf_paper_size  ) ) {
			$_dompdf_paper_size[3] = $GLOBALS['wpo_wcpdf_dompdf_body_height'] + 150; // if too many space at the bottom, replace this 150 value with a lower one
		}

		$dompdf = new \Dompdf\Dompdf( $_dompdf_options );
		$dompdf->loadHtml( $html );
		$dompdf->setPaper( $_dompdf_paper_size, $_dompdf_paper_orientation );
		
		return $dompdf;
	} else {
		return $_dompdf;
	}
}, 10, 4 );

add_action( 'wpo_wcpdf_before_document', function ( $document_type, $document ) {
	if ( 'receipt' === $document_type ) {
		?>
		<style>
			@page {
				margin: 5mm;
			}
			.head,
			.head > tr,
			.head > tr > td,
			.head > tbody,
			.head > tbody > tr,
			.head > tbody > tr > td,
			.order-data-addresses,
			.order-data-addresses > tr,
			.order-data-addresses > tr > td,
			.order-data-addresses > tbody,
			.order-data-addresses > tbody > tr,
			.order-data-addresses > tbody > tr > td {
				display: block;
			}

			.head > tbody > tr > td,
			.order-data-addresses > tbody > tr > td {
				width:100%!important;
				padding-bottom: 4mm; 
			}

			.order-details > tfoot > tr > td.no-borders:first-child {
				width:25%;
			}
		</style>
		<?php
	}
}, 10, 2 );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants