PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.0
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.0
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
← All changes | templates/quote-templates/standard.php +90 -25 2.3.6 → 2.4.0 View file →
@@ -3,8 +3,11 @@
3 3 * Standard Quote Template - Clean SaaS Design
4 4 * Clean, modern, and professional quote template
5 5 */
6 6
7 +if ( ! defined( 'ABSPATH' ) ) {
8 + exit;
9 +}
7 10 $text_settings = \EasyInvoice\Helpers\TemplateTextHelper::getQuoteTextSettings();
8 11 $company_info = \EasyInvoice\Helpers\TemplateTextHelper::getCompanyInfo();
9 12 // Ensure a formatter is available for currency formatting
10 13 if (!isset($formatter) || !$formatter) {
@@ -227,26 +230,70 @@
227 230 .template-standard .quote-totals {
228 231 width: 100%;
229 232 }
230 233 }
234 +
235 +/* Shared polish: numbers line up, numeric headings sit over their figures. */
236 +.template-standard .quote-items th + th { text-align: right; }
237 +.template-standard .quote-items .item-quantity,
238 +.template-standard .quote-items .item-price,
239 +.template-standard .quote-items .item-adjust,
240 +.template-standard .quote-items .item-total,
241 +.template-standard .quote-total-value { font-variant-numeric: tabular-nums; white-space: nowrap; }
242 +.template-standard .meta-value { white-space: nowrap; }
243 +.template-standard .quote-items .item-adjust { text-align: right; }
244 +.template-standard .client-contact { font-weight: 500; margin-bottom: 0.15em; }
245 +.template-standard .client-tax-number,
246 +.template-standard .company-tax-number { margin-top: 0.35em; }
247 +.template-standard .quote-items .item-description { white-space: pre-line; }
248 +.template-standard .document-kind { display: block; font-size: 0.72rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-muted, #8a8a8a); font-family: var(--font-family-body, inherit); font-style: normal; margin-bottom: 0.3em; line-height: 1.2; }
249 +
250 +/* Standard: ink on white, one rule per section, nothing boxed. */
251 +.template-standard { color: #1f2937; }
252 +.template-standard .quote-header { border-bottom: 2px solid #1f2937; padding-bottom: 1.5rem; margin-bottom: 1.75rem; align-items: flex-start; }
253 +.template-standard .company-name { font-size: 1.375rem; font-weight: 700; letter-spacing: -0.01em; color: #111827; }
254 +.template-standard .company-details, .template-standard .address-content, .template-standard .meta-label, .template-standard .quote-total-label { color: #6b7280; }
255 +.template-standard .quote-title { font-size: 1.625rem; font-weight: 700; letter-spacing: -0.015em; color: #111827; margin-bottom: 0.75rem; }
256 +.template-standard .meta-item { display: flex; justify-content: flex-end; gap: 1rem; margin-bottom: 0.35rem; font-size: 0.9rem; }
257 +.template-standard .meta-value { font-weight: 600; color: #111827; }
258 +.template-standard .address-block { background: transparent; padding: 0; border: 0; }
259 +.template-standard .address-block h2 { font-size: 0.72rem; letter-spacing: 0.14em; color: #6b7280; margin-bottom: 0.5rem; }
260 +.template-standard .client-name { font-weight: 600; color: #111827; font-size: 1rem; }
261 +.template-standard .quote-items { border: 0; margin-bottom: 1.25rem; }
262 +.template-standard .quote-items th { background: transparent; color: #6b7280; font-size: 0.72rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; padding: 0.6rem 0.5rem; border-bottom: 1px solid #1f2937; }
263 +.template-standard .quote-items td { padding: 0.8rem 0.5rem; border-bottom: 1px solid #e5e7eb; color: #1f2937; }
264 +.template-standard .quote-items th:first-child, .template-standard .quote-items td:first-child { padding-left: 0; }
265 +.template-standard .quote-items th:last-child, .template-standard .quote-items td:last-child { padding-right: 0; }
266 +.template-standard .item-name .item-title { font-weight: 600; color: #111827; }
267 +.template-standard .item-description { font-weight: 400; color: #6b7280; font-size: 0.85rem; }
268 +.template-standard .quote-totals { width: 320px; margin-bottom: 1.5rem; }
269 +.template-standard .quote-total-row { padding: 0.45rem 0; border-bottom: 1px solid #e5e7eb; font-size: 0.95rem; }
270 +.template-standard .quote-total-value { font-weight: 600; color: #111827; }
271 +.template-standard .quote-totals .quote-grand-total { border-top: 2px solid #1f2937; border-bottom: 0; margin-top: 0.25rem; padding-top: 0.75rem; font-size: 1.125rem; }
272 +.template-standard .quote-totals .quote-grand-total .quote-total-label { color: #111827; font-weight: 700; }
273 +.template-standard .quote-totals .quote-grand-total .quote-total-value { font-size: 1.25rem; font-weight: 700; }
274 +.template-standard .quote-notes, .template-standard .quote-terms { background: transparent; padding: 1.25rem 0 0; margin-top: 1.25rem; border: 0; border-top: 1px solid #e5e7eb; border-radius: 0; color: #4b5563; font-size: 0.9rem; }
275 +.template-standard .quote-notes h3, .template-standard .quote-terms h3 { font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: #6b7280; font-weight: 600; margin-bottom: 0.5rem; }
276 +.template-standard .quote-footer { border-top: 1px solid #e5e7eb; color: #6b7280; font-size: 0.85rem; }
231 277 </style>
232 278
233 279 <div class="template template-standard">
234 280 <div class="quote-header">
235 281 <div class="company-info">
282 + <?php if (!empty($company_info['logo'])): ?>
236 283 <div class="company-logo">
237 - <?php if (!empty($company_info['logo'])): ?>
238 - <img src="<?php echo esc_url($company_info['logo']); ?>" alt="<?php echo esc_attr($company_info['name']); ?>" class="logo-image">
239 - <?php endif; ?>
284 + <img src="<?php echo esc_url($company_info['logo']); ?>" alt="<?php echo esc_attr($company_info['name']); ?>" class="logo-image" onerror="this.parentNode.parentNode.removeChild(this.parentNode)">
240 285 </div>
286 + <?php endif; ?>
241 287 <div class="company-name"><?php echo esc_html($company_info['name']); ?></div>
242 288 <div class="company-details">
243 - <?php echo \EasyInvoice\Helpers\TemplateTextHelper::generateFromSection($company_info, false, 'details-only'); ?>
289 + <?php echo wp_kses_post(\EasyInvoice\Helpers\TemplateTextHelper::generateFromSection($company_info, false, 'details-only')); ?>
244 290 </div>
245 291 </div>
246 292
247 293 <div class="quote-meta">
248 - <div class="quote-title"><?php echo esc_html($quote->getTitle() ?: __('Quote', 'easy-invoice')); ?></div>
294 + <?php $ei_kind = \EasyInvoice\Controllers\SettingsController::getTextQuote(); $ei_title = trim((string) $quote->getTitle()); ?>
295 + <div class="quote-title"><?php if ('' !== $ei_title && 0 !== strcasecmp($ei_title, $ei_kind)) : ?><span class="document-kind"><?php echo esc_html($ei_kind); ?></span><?php endif; ?><?php echo esc_html('' !== $ei_title ? $ei_title : $ei_kind); ?></div>
249 296 <div class="meta-item">
250 297 <span class="meta-label"><?php echo esc_html($text_settings['quote_number']); ?></span>
251 298 <span class="meta-value"><?php echo esc_html($quote->getNumber()); ?></span>
252 299 </div>
@@ -260,22 +307,18 @@
260 307 </div>
261 308 </div>
262 309 </div>
263 310
311 + <?php $ei_client_html = \EasyInvoice\Helpers\TemplateTextHelper::generateClientBlock($quote); if ('' !== $ei_client_html) : ?>
264 312 <div class="address-section">
265 313 <div class="address-block">
266 314 <h2><?php echo esc_html($text_settings['to']); ?></h2>
267 315 <div class="address-content">
268 - <div class="client-name"><?php echo esc_html($quote->getCustomerName()); ?></div>
269 - <?php if ($quote->getCustomerAddress()): ?>
270 - <?php echo nl2br(esc_html($quote->getCustomerAddress())); ?><br>
271 - <?php endif; ?>
272 - <?php if ($quote->getCustomerEmail()): ?>
273 - <?php echo esc_html($quote->getCustomerEmail()); ?><br>
274 - <?php endif; ?>
316 + <?php echo wp_kses_post($ei_client_html); ?>
275 317 </div>
276 318 </div>
277 319 </div>
320 + <?php endif; ?>
278 321
279 322 <?php if ($quote->getDescription()): ?>
280 323 <div class="quote-description">
281 324 <div class="description-content"><?php echo wp_kses_post($quote->getDescription()); ?></div>
@@ -281,8 +324,18 @@
281 324 <div class="description-content"><?php echo wp_kses_post($quote->getDescription()); ?></div>
282 325 </div>
283 326 <?php endif; ?>
284 327
328 + <?php
329 + // The adjustment column appears only when at least one line uses it.
330 + $ei_show_adjust = \EasyInvoice\Controllers\SettingsController::shouldShowQuoteAdjustField();
331 + if ($ei_show_adjust) {
332 + $ei_show_adjust = false;
333 + foreach ($quote->getItems() as $ei_item) {
334 + if ((float) $ei_item->getAdjustPercentage() != 0.0) { $ei_show_adjust = true; break; }
335 + }
336 + }
337 + ?>
285 338 <table class="quote-items">
286 339 <thead>
287 340 <tr>
288 341 <th><?php echo esc_html($text_settings['service']); ?></th>
@@ -287,15 +340,18 @@
287 340 <tr>
288 341 <th><?php echo esc_html($text_settings['service']); ?></th>
289 342 <th><?php echo esc_html($text_settings['qty']); ?></th>
290 343 <th><?php echo esc_html($text_settings['rate_price']); ?></th>
291 - <?php if (\EasyInvoice\Controllers\SettingsController::shouldShowQuoteAdjustField()): ?>
344 + <?php if ($ei_show_adjust): ?>
292 345 <th><?php echo esc_html($text_settings['adjust']); ?> (%)</th>
293 346 <?php endif; ?>
294 - <th><?php echo esc_html($text_settings['total']); ?></th>
347 + <th><?php echo esc_html($text_settings['line_total'] ?? $text_settings['total']); ?></th>
295 348 </tr>
296 349 </thead>
297 350 <tbody>
351 + <?php if (!$quote->getItems()) : ?>
352 + <tr class="no-items"><td colspan="<?php echo $ei_show_adjust ? 5 : 4; ?>" style="text-align:center;color:#9ca3af;padding:18px;"><?php esc_html_e('No items yet.', 'easy-invoice'); ?></td></tr>
353 + <?php endif; ?>
298 354 <?php foreach ($quote->getItems() as $item): ?>
299 355 <tr>
300 356 <td class="item-name">
301 357 <div class="item-title"><?php echo esc_html($item->getName()); ?></div>
@@ -304,9 +360,9 @@
304 360 <?php endif; ?>
305 361 </td>
306 362 <td class="item-quantity"><?php echo esc_html($item->getQuantity() ?: '0'); ?></td>
307 363 <td class="item-price"><?php echo esc_html($formatter->format($item->getPrice())); ?></td>
308 - <?php if (\EasyInvoice\Controllers\SettingsController::shouldShowQuoteAdjustField()): ?>
364 + <?php if ($ei_show_adjust): ?>
309 365 <td class="item-adjust"><?php
310 366 $adjust_percentage = $item->getAdjustPercentage();
311 367 if ($adjust_percentage != 0) {
312 368 echo esc_html($adjust_percentage > 0 ? '+' : '') . esc_html($adjust_percentage) . '%';
@@ -321,14 +377,14 @@
321 377 </tbody>
322 378 </table>
323 379
324 380 <div class="quote-totals">
325 - <?php echo \EasyInvoice\Helpers\TemplateTextHelper::generateTotalsSection($quote, $text_settings, $formatter, 'quote'); ?>
381 + <?php echo wp_kses_post(\EasyInvoice\Helpers\TemplateTextHelper::generateTotalsSection($quote, $text_settings, $formatter, 'quote')); ?>
326 382 </div>
327 383
328 384 <?php if ($quote->getNotes()): ?>
329 385 <div class="quote-notes">
330 - <h3><?php _e('Notes:', 'easy-invoice'); ?></h3>
386 + <h3><?php esc_html_e('Notes', 'easy-invoice'); ?></h3>
331 387 <div class="notes-content">
332 388 <?php echo wp_kses_post($quote->getNotes() ?: ''); ?>
333 389 </div>
334 390 </div>
@@ -338,9 +394,9 @@
338 394 $terms_conditions = $quote->getTerms() ?: \EasyInvoice\Controllers\SettingsController::getQuoteTermsConditions();
339 395 if ($terms_conditions):
340 396 ?>
341 397 <div class="quote-terms">
342 - <h3><?php _e('Terms & Conditions:', 'easy-invoice'); ?></h3>
398 + <h3><?php esc_html_e('Terms & Conditions', 'easy-invoice'); ?></h3>
343 399 <div class="terms-content">
344 400 <?php echo wp_kses_post($terms_conditions); ?>
345 401 </div>
346 402 </div>
@@ -345,14 +401,23 @@
345 401 </div>
346 402 </div>
347 403 <?php endif; ?>
348 404
405 + <?php
406 + /**
407 + * Fires inside the document card, after notes and terms and before the
408 + * footer text: attachments, the signature block, e-invoicing notes. Being
409 + * inside the card, it is part of what "Download as PDF" captures.
410 + *
411 + * @param object $document The quote model.
412 + * @param string $type 'quote'.
413 + */
414 + do_action('easy_invoice_document_body_after', $quote, 'quote');
415 +
416 + $ei_footer_text = \EasyInvoice\Helpers\TemplateTextHelper::footerText($quote, 'quote');
417 + if ('' !== trim(wp_strip_all_tags((string) $ei_footer_text))) :
418 + ?>
349 419 <div class="quote-footer">
350 - <?php
351 - $footer_text = $quote->getFooterText();
352 - if (!$footer_text) {
353 - $footer_text = \EasyInvoice\Controllers\SettingsController::getQuoteFooterText();
354 - }
355 - ?>
356 - <p><?php echo wp_kses_post($footer_text); ?></p>
420 + <p><?php echo wp_kses_post($ei_footer_text); ?></p>
357 421 </div>
422 + <?php endif; ?>
358 423 </div>