phpphpoffice-phpspreadsheet

How to display images in Excel output using the phpspreadsheet library


I have developed a function to output a series of information in WordPress and I use the phpspreadsheet library to output the information. I followed the documentation of the phpspreadsheet site, but I am facing this error:

Fatal error: Uncaught PhpOffice\PhpSpreadsheet\Writer\Exception: File http://persis.local/wp-content/uploads/2023/02/Thousand-Way-Long-Coat-01.jpg does not exist in E:\xampp\htdocs\persis.local\wp-content\plugins\by-products\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx\ContentTypes.php:226 Stack trace: #0 E:\xampp\htdocs\persis.local\wp-content\plugins\by-products\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx\ContentTypes.php(137): PhpOffice\PhpSpreadsheet\Writer\Xlsx\ContentTypes->getImageMimeType('http://persis.l...') #1 E:\xampp\htdocs\persis.local\wp-content\plugins\by-products\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php(332): PhpOffice\PhpSpreadsheet\Writer\Xlsx\ContentTypes->writeContentTypes(Object(PhpOffice\PhpSpreadsheet\Spreadsheet), false) #2 E:\xampp\htdocs\persis.local\wp-content\plugins\by-products\by-products.php(572): PhpOffice\PhpSpreadsheet\Writer\Xlsx->save('purchase_order_...') #3 E:\xampp\htdocs\persis.local\wp-includes\class-wp-hook.php(308): in E:\xampp\htdocs\persis.local\wp-content\plugins\by-products\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx\ContentTypes.php on line 226

I searched a bit and made a series of changes in my code, but it didn't make any difference, the error is still there. This is my code:

require_once 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

/**
 * @throws \PhpOffice\PhpSpreadsheet\Exception
 * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
 */
function bp_display_purchase_order_info_callback() {
    echo '<div class="wrap">';
    echo '<h1>Purchase Order Information</h1>';
    echo '<table class="wp-list-table widefat fixed striped">';
    echo '<thead>';
    echo '<tr>';
    echo '<th scope="col">Product Photo</th>';
    echo '<th scope="col">Product Name</th>';
    echo '<th scope="col">SKU</th>';
    echo '<th scope="col">Number of Purchases</th>';
    echo '<th scope="col">Producer Name</th>';
    echo '<th scope="col">Last Price</th>';
    echo '</tr>';
    echo '</thead>';
    echo '<tbody>';

    // Query the products to retrieve their details
    $args = array(
        'post_type'      => 'product',
        'posts_per_page' => - 1,
        'orderby'        => 'modified', // Sort by the update date
        'order'          => 'DESC',     // Sort in descending order (newest to oldest)
    );


    $products = new WP_Query( $args );

    if ( $products->have_posts() ) {
        while ( $products->have_posts() ) {
            $products->the_post();

            // Get product details
            $product_id    = get_the_ID();
            $product       = wc_get_product( $product_id );
            $product_name  = $product->get_name();
            $product_sku   = $product->get_sku();
            $product_image = get_the_post_thumbnail_url( $product_id, 'thumbnail' );

            // Get custom "Purchase Quantity" field value
            $purchase_quantity = get_post_meta( $product_id, '_purchase_quantity', true );

            // Get the latest price information
            $last_price   = '';
            $vendor_name  = '';
            $price_change = '';

            if ( have_rows( 'details', $product_id ) ) {
                $rows         = get_field( 'details', $product_id );
                $last_row     = end( $rows );
                $last_price   = $last_row['price'];
                $vendor_name  = $last_row['vendor_name'];
                $price_change = $last_row['price_change'];
            }

            // Display the product only if it has a "Number of Purchases" value
            if ( $purchase_quantity > 0 ) {
                echo '<tr>';
                echo '<td><img src="' . $product_image . '" alt="' . $product_name . '" style="max-width: 100px;"></td>';
                echo '<td>' . $product_name . '</td>';
                echo '<td>' . $product_sku . '</td>';
                echo '<td>' . $purchase_quantity . '</td>';
                echo '<td>' . $vendor_name . '</td>';
                echo '<td>';

                if ( $last_price ) {
                    $price_text = '';

                    if ( ! empty( $price_change ) && strcasecmp( $price_change, 'yes' ) == 0 ) {
                        $price_text .= '<span style="color: #fff; background: #ff0000; padding: 1px 3px; font-weight: bolder;">' . $last_price . '</span>';
                    } else {
                        $price_text .= $last_price;
                    }

                    echo $price_text;
                }

                echo '</td>';
                echo '</tr>';
            }
        }
        wp_reset_postdata();
    } else {
        echo '<tr><td colspan="7">No products found.</td></tr>';
    }

    echo '</tbody>';
    echo '</table>';


    // Create a new Spreadsheet object
    $spreadsheet = new Spreadsheet();
    $sheet       = $spreadsheet->getActiveSheet();


    // Add column headers
    $sheet->setCellValue( 'A1', 'Product Photo' );
    $sheet->setCellValue( 'B1', 'Product Name' );
    $sheet->setCellValue( 'C1', 'SKU' );
    $sheet->setCellValue( 'D1', 'Number of Purchases' );
    $sheet->setCellValue( 'E1', 'Producer Name' );
    $sheet->setCellValue( 'F1', 'Last Price' );

    // Set column headers style
    $headerStyle = $sheet->getStyle( 'A1:F1' );
    $headerStyle->getFont()->setBold( true );
    $headerStyle->getAlignment()->setHorizontal( \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER );
    $headerStyle->getBorders()->getAllBorders()->setBorderStyle( \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN );

    $row = 2; // Start from row 2 for data

    // Loop through the products and add data to the Excel sheet
    if ( $products->have_posts() ) {
        while ( $products->have_posts() ) {
            $products->the_post();

            // Get product details
            $product_id    = get_the_ID();
            $product       = wc_get_product( $product_id );
            $product_name  = $product->get_name();
            $product_sku   = $product->get_sku();
            $product_image = get_the_post_thumbnail_url( $product_id, 'thumbnail' );

            // Get custom "Purchase Quantity" field value
            $purchase_quantity = get_post_meta( $product_id, '_purchase_quantity', true );

            // Get the latest price information
            $last_price   = '';
            $vendor_name  = '';
            $price_change = '';

            if ( have_rows( 'details', $product_id ) ) {
                $rows         = get_field( 'details', $product_id );
                $last_row     = end( $rows );
                $last_price   = $last_row['price'];
                $vendor_name  = $last_row['vendor_name'];
                $price_change = $last_row['price_change'];
            }

            // Display the product only if it has a "Number of Purchases" value
            if ( $purchase_quantity > 0 ) {

                $drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
                $drawing->setName( 'Product Image' );
                $drawing->setDescription( 'Product Image' );
                $drawing->setPath( $product_image ); /* put your path and image here */
                $drawing->setCoordinates( 'A1' );
                $drawing->setOffsetX( 110 );
                $drawing->setRotation( 25 );
                $drawing->getShadow()->setVisible( true );
                $drawing->getShadow()->setDirection( 45 );
                $drawing->setWorksheet( $spreadsheet->getActiveSheet() );

                // Add data to the Excel sheet
                $sheet->setCellValue( 'A' . $row, $product_image );
                $sheet->setCellValue( 'B' . $row, $product_name );
                $sheet->setCellValue( 'C' . $row, $product_sku );
                $sheet->setCellValue( 'D' . $row, $purchase_quantity );
                $sheet->setCellValue( 'E' . $row, $vendor_name );
                $sheet->setCellValue( 'F' . $row, $last_price );

                $row ++;
            }
        }
        wp_reset_postdata();
    }

    // Adjust the column widths
    foreach ( range( 'A', 'F' ) as $column ) {
        $sheet->getColumnDimension( $column )->setAutoSize( true );
    }

    // Set the filename for the Excel file
    $filename = 'purchase_order_info.xlsx';

    // Save the Excel file
    $writer = new Xlsx( $spreadsheet );
    $writer->save( $filename );

    // Output a link to download the Excel file
    echo '<p style="position: absolute;top: 75px;right: 20px;"><a class="button button-primary" href="' . $filename . '">Download Excel File</a></p>';

    echo '</div>';
}

I checked the codes several times and made several changes, but the problem is in the location. How can I solve this problem?


Solution

  • The error you are getting is because you have not specified the photo path correctly in part :

    // Display the product only if it has a "Number of Purchases" value
    if ( $purchase_quantity > 0 ) {
    

    Add the following codes:

             if ($product_image) {
                        $parsed_url = parse_url($product_image);
                        $absolute_path = rtrim(ABSPATH, '/') . $parsed_url['path'];
    
                        if (file_exists($absolute_path)) {
                            $drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
                            $drawing->setName('Product Image');
                            $drawing->setDescription('Product Image');
                            $drawing->setPath($absolute_path); // Use the absolute path here
                            $drawing->setHeight(150);
                            $drawing->setWidth(150);
                            $drawing->setCoordinates('A' . $row);
                            $drawing->setWorksheet($sheet);
                            // Set row height to accommodate the image
                            $sheet->getRowDimension($row)->setRowHeight(150);  // Adjust this based on your needs
                        } else {
                            $sheet->setCellValue('A' . $row, 'Image Not Found');
                        }
                    } else {
                        $sheet->setCellValue('A' . $row, 'No Image');
                    }
                    // Set column width for column 'A'
                    $sheet->getColumnDimension('A')->setWidth(150);  // Adjust this based on your needs
    
                    $sheet->setCellValue( 'B' . $row, $product_name );
                    $sheet->setCellValue( 'C' . $row, $product_sku );
                    $sheet->setCellValue( 'D' . $row, $purchase_quantity );
                    $sheet->setCellValue( 'E' . $row, $vendor_name );
                    $sheet->setCellValue( 'F' . $row, $last_price );
                    $sheet->setCellValue( 'G' . $row, $order_date );
                    $sheet->setCellValue( 'H' . $row, $purchase_date );
                    $sheet->setCellValue( 'I' . $row, $delivery_date );
                    $sheet->setCellValue( 'J' . $row, $bp_description );
    
                    $row ++;
    

    It should be noted that it is no longer necessary to go to the $sheet->setCellValue( 'A' . $row, $product_image ); section