// 5 START: Action — Generate Folder Images (overwrite) with GD/TTF, auto-detect size, text = Post Name “{Folder} Media”, refresh thumbnails
function gmm_temp_action_generate_folder_images() {
if (!current_user_can('manage_options')) { return 'Not allowed.'; }
check_admin_referer('gmm_temp_gen_folder_images');
if (!extension_loaded('gd')) {
return 'PHP GD extension is not available. Please enable GD or ask hosting support.';
}
$root = get_option(GMM_TEMP_OPT_ROOT, '');
$real = $root ? realpath($root) : false;
if (!$real || !is_dir($real)) {
return 'Root path is not valid. Set it and save first.';
}
$real = wp_normalize_path($real);
// --- Detect target size (featured > large > fallback) ---
$W = 0; $H = 0;
if (isset($GLOBALS['_wp_additional_image_sizes']['post-thumbnail'])) {
$sz = $GLOBALS['_wp_additional_image_sizes']['post-thumbnail'];
$W = !empty($sz['width']) ? (int)$sz['width'] : 0;
$H = !empty($sz['height']) ? (int)$sz['height'] : 0;
}
if ($W <= 0 || $H <= 0) { $W = (int) get_option('large_size_w', 0); $H = (int) get_option('large_size_h', 0); }
if ($W <= 0 || $H <= 0) { $W = 1200; $H = 630; } // last resort
// --- Find a TTF font (fallback to bitmap if none) ---
$font_candidates = [
'/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
'/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf',
'/usr/share/fonts/truetype/freefont/FreeSansBold.ttf',
'/Library/Fonts/Arial Bold.ttf',
'/System/Library/Fonts/Supplemental/Arial Bold.ttf',
'C:\\Windows\\Fonts\\arialbd.ttf',
];
$FONT = '';
foreach ($font_candidates as $f) { if (is_file($f)) { $FONT = $f; break; } }
$has_ttf = $FONT && function_exists('imagettfbbox') && function_exists('imagettftext');
// Helpers
$draw_gradient = function(&$im, $w, $h, $hexTop, $hexBot) {
$hex_to_rgb = function($hex){ $hex = ltrim($hex, '#'); return [hexdec(substr($hex,0,2)),hexdec(substr($hex,2,2)),hexdec(substr($hex,4,2))]; };
list($r1,$g1,$b1) = $hex_to_rgb($hexTop);
list($r2,$g2,$b2) = $hex_to_rgb($hexBot);
for ($y=0; $y<$h; $y++) {
$t = $h>1 ? $y/($h-1) : 0;
$r = (int) round($r1 + ($r2-$r1)*$t);
$g = (int) round($g1 + ($g2-$g1)*$t);
$b = (int) round($b1 + ($b2-$b1)*$t);
$col = imagecolorallocate($im, $r, $g, $b);
imageline($im, 0, $y, $w, $y, $col);
}
imagefilledrectangle($im, 0, (int)($h*0.72), $w, $h, imagecolorallocatealpha($im, 0,0,0,100));
};
$fit_text = function($title, $w, $h, $fontPath) {
$padX = (int) round($w * 0.08);
$padY = (int) round($h * 0.08);
$boxW = $w - 2*$padX;
$boxH = $h - 2*$padY;
$measure = function($size, $txt) use ($fontPath) {
$bb = imagettfbbox($size, 0, $fontPath, $txt);
$width = abs($bb[2]-$bb[0]);
$height = abs($bb[7]-$bb[1]);
return [$width, $height];
};
$text = trim($title);
$lines = [$text];
$maxSize = (int) max(18, min($boxH * 0.45, $boxW * 0.20));
$minSize = 14;
$bestSize = $minSize;
for ($s=$maxSize; $s>=$minSize; $s-=2) {
list($tw,$th) = $measure($s, $text);
if ($tw <= $boxW && $th <= $boxH*0.6) { $bestSize=$s; break; }
}
list($tw,$th) = $measure($bestSize, $text);
if ($tw > $boxW && strpos($text,' ') !== false) {
$parts = preg_split('~\s+~', $text);
$N = count($parts);
$mid = (int) floor($N/2);
$candidates = [];
for ($i=max(1,$mid-2); $i<=min($N-1,$mid+2); $i++) {
$candidates[] = [implode(' ', array_slice($parts,0,$i)), implode(' ', array_slice($parts,$i))];
}
$best = $candidates[0]; $bestDiff = PHP_INT_MAX;
foreach ($candidates as $cand) {
$d = abs(strlen($cand[0]) - strlen($cand[1]));
if ($d < $bestDiff) { $bestDiff=$d; $best=$cand; }
}
$lines = [$best[0], $best[1]];
$maxSize2 = (int) max(18, min($boxH * 0.60, $boxW * 0.22));
$bestSize = $minSize;
for ($s=$maxSize2; $s>=$minSize; $s-=2) {
list($w1,$h1) = $measure($s, $lines[0]);
list($w2,$h2) = $measure($s, $lines[1]);
$totalH = $h1 + (int)($s*0.35) + $h2;
if (max($w1,$w2) <= $boxW && $totalH <= $boxH) { $bestSize=$s; break; }
}
}
return [$lines, $bestSize];
};
$created = 0; $refreshed = 0; $thumbs_set = 0; $errors = 0;
$list = @scandir($real);
if (!is_array($list)) { return 'Unable to read the root folder.'; }
foreach ($list as $base) {
if ($base === '.' || $base === '..' || $base[0] === '.') { continue; }
$abs = wp_normalize_path($real.'/'.$base);
if (!is_dir($abs)) { continue; }
$slug = sanitize_title($base);
$folder_title = ucwords(trim(preg_replace('~[_\-]+~', ' ', pathinfo($base, PATHINFO_FILENAME))));
$post_title = $folder_title . ' Media'; // <- use Post Name text
$target_jpg = $abs.'/'.$slug.'.jpg'; // always (re)write .jpg
// --- (Re)generate image file (overwrite) ---
$im = imagecreatetruecolor($W, $H);
if (!$im) { $errors++; continue; }
// Gradient per folder (stable, varied)
$seed = crc32($slug);
$hue = $seed % 360;
$toRgb = function($h,$s,$l){
$c = (1 - abs(2*$l - 1)) * $s;
$x = $c * (1 - abs(fmod($h/60,2) - 1));
$m = $l - $c/2;
switch (true) {
case $h<60: list($r,$g,$b)=[$c,$x,0]; break;
case $h<120: list($r,$g,$b)=[$x,$c,0]; break;
case $h<180: list($r,$g,$b)=[0,$c,$x]; break;
case $h<240: list($r,$g,$b)=[0,$x,$c]; break;
case $h<300: list($r,$g,$b)=[$x,0,$c]; break;
default: list($r,$g,$b)=[$c,0,$x]; break;
}
return [ (int)(($r+$m)*255), (int)(($g+$m)*255), (int)(($b+$m)*255) ];
};
list($r1,$g1,$b1) = $toRgb($hue, 0.55, 0.35);
list($r2,$g2,$b2) = $toRgb(($hue+20)%360, 0.55, 0.55);
$hexTop = sprintf('#%02x%02x%02x',$r1,$g1,$b1);
$hexBot = sprintf('#%02x%02x%02x',$r2,$g2,$b2);
$draw_gradient($im, $W, $H, $hexTop, $hexBot);
if ($has_ttf) {
list($lines, $size) = $fit_text($post_title, $W, $H, $FONT);
$shadow = imagecolorallocatealpha($im, 0,0,0,60);
$white = imagecolorallocate($im, 255,255,255);
$measure = function($s,$t) use ($FONT) { $bb=imagettfbbox($s,0,$FONT,$t); return [abs($bb[2]-$bb[0]), abs($bb[7]-$bb[1])]; };
$gap = (int) ($size * 0.35);
$heights = []; $widths = [];
foreach ($lines as $ln) { list($w1,$h1) = $measure($size,$ln); $widths[]=$w1; $heights[]=$h1; }
$totalH = array_sum($heights) + $gap * (count($lines)-1);
$xCenter = (int) ($W / 2);
$y = (int) (($H - $totalH) / 2);
foreach ($lines as $idx => $ln) {
list($wLine,$hLine) = $measure($size,$ln);
$x = $xCenter - (int)($wLine/2);
$y += $hLine;
imagettftext($im, $size, 0, $x+2, $y+2, $shadow, $FONT, $ln);
imagettftext($im, $size, 0, $x, $y, $white, $FONT, $ln);
$y += $gap;
}
} else {
// Bitmap fallback with contrast bar
$barH = (int) max(24, $H * 0.18);
$barY = (int) (($H - $barH) / 2);
$bar = imagecolorallocatealpha($im, 0,0,0,80);
imagefilledrectangle($im, 0, $barY, $W, $barY+$barH, $bar);
$white = imagecolorallocate($im,255,255,255);
$font = 5; $fw = imagefontwidth($font); $fh = imagefontheight($font);
$tw = $fw * strlen($post_title);
$x = max(6, (int)(($W - $tw) / 2));
$y = (int)(($H - $fh) / 2);
imagestring($im, $font, $x, $y, $post_title, $white);
}
if (!@imagejpeg($im, $target_jpg, 88)) { $errors++; imagedestroy($im); continue; }
@chmod($target_jpg, 0644);
imagedestroy($im);
$created++;
// --- Refresh Media Library attachment & featured image ---
// Find a post for this folder (if any)
$meta_path = trailingslashit($abs);
$existing_post = get_posts([
'post_type' => 'post',
'post_status' => 'any',
'meta_key' => 'gmm_path',
'meta_value' => $meta_path,
'fields' => 'ids',
'posts_per_page' => 1,
'no_found_rows' => true,
'suppress_filters' => true,
]);
if (!empty($existing_post)) {
$post_id = (int)$existing_post[0];
// If we already have an attachment for this source abs, update its file in uploads; else import new
$reuse = function_exists('gmm_temp_find_attachment_by_source_abs') ? gmm_temp_find_attachment_by_source_abs($target_jpg) : 0;
if ($reuse) {
$dest = get_attached_file($reuse);
if ($dest && @copy($target_jpg, $dest)) {
if (function_exists('wp_update_image_subsizes')) {
@wp_update_image_subsizes($reuse);
} else {
$meta = @wp_generate_attachment_metadata($reuse, $dest);
if ($meta) { @wp_update_attachment_metadata($reuse, $meta); }
}
set_post_thumbnail($post_id, $reuse);
$thumbs_set++;
} else {
// fallback: re-import
if (function_exists('gmm_temp_attach_local_image')) {
$att_id = gmm_temp_attach_local_image($post_id, $target_jpg, $post_title);
if ($att_id) { $thumbs_set++; }
}
}
} else {
if (function_exists('gmm_temp_attach_local_image')) {
$att_id = gmm_temp_attach_local_image($post_id, $target_jpg, $post_title);
if ($att_id) { $thumbs_set++; }
}
}
$refreshed++;
}
}
$msg = 'Folder Images: regenerated '.$created;
$msg .= ', refreshed posts '.$refreshed;
$msg .= ', set thumbnails '.$thumbs_set;
$msg .= $errors ? ', errors '.$errors : '';
$msg .= '. Generated at '.$W.'×'.$H.( $has_ttf ? ' using TTF anti-aliased text.' : ' (fallback bitmap text).' ).'';
return $msg;
}
// 5 STOP: Action — Generate Folder Images (overwrite) with GD/TTF, auto-detect size, text = Post Name “{Folder} Media”, refresh thumbnails
Today – Moon Points – Moon – Gameznet Creators Hub
Scroll to top