Issues (1686)

sources/subs/Themes.subs.php (2 issues)

1
<?php
2
3
/**
4
 * This file contains functions for dealing with themes, adding, removing
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * @version 2.0 dev
11
 *
12
 */
13
14
use ElkArte\Helper\HttpReq;
15
use ElkArte\Helper\Util;
16
use ElkArte\Languages\Loader as LangLoader;
17
use ElkArte\Languages\Txt;
18
use ElkArte\Themes\ThemeLoader;
19
20
/**
21
 * Retrieve all installed themes
22
 */
23
function installedThemes()
24
{
25
	$db = database();
26
27
	$themes = [];
28
	$db->fetchQuery('
29
		SELECT 
30
			id_theme, variable, value
31
		FROM {db_prefix}themes
32
		WHERE variable IN ({string:name}, {string:theme_dir}, {string:theme_url}, {string:images_url}, {string:theme_templates}, {string:theme_layers})
33
			AND id_member = {int:no_member}',
34
		[
35
			'name' => 'name',
36
			'theme_dir' => 'theme_dir',
37
			'theme_url' => 'theme_url',
38
			'images_url' => 'images_url',
39
			'theme_templates' => 'theme_templates',
40
			'theme_layers' => 'theme_layers',
41
			'no_member' => 0,
42
		]
43
	)->fetch_callback(
44
		function ($row) use (&$themes) {
45
			if (!isset($themes[$row['id_theme']]))
46
			{
47
				$themes[$row['id_theme']] = [
48
					'id' => $row['id_theme'],
49
					'num_default_options' => 0,
50
					'num_members' => 0,
51
				];
52
			}
53
54
			$themes[$row['id_theme']][$row['variable']] = $row['value'];
55
		}
56
	);
57
58
	return $themes;
59
}
60
61
/**
62
 * Validates a theme name
63
 *
64
 * @param array $indexes
65
 * @param array $value_data
66
 *
67
 * @return array
68
 */
69
function validateThemeName($indexes, $value_data)
70
{
71
	$db = database();
72
73
	$themes = [];
74
	$db->fetchQuery('
75
		SELECT 
76
			id_theme, value
77
		FROM {db_prefix}themes
78
		WHERE id_member = {int:no_member}
79
			AND variable = {string:theme_dir}
80
			AND (' . implode(' OR ', $value_data['query']) . ')',
81
		array_merge($value_data['params'], [
82
			'no_member' => 0,
83
			'theme_dir' => 'theme_dir',
84
			'index_compare_explode' => 'value LIKE \'%' . implode('\' OR value LIKE \'%', $indexes) . '\'',
85
		])
86
	)->fetch_callback(
87
		function ($row) use (&$themes, $indexes) {
88
			// Find the right one.
89
			foreach ($indexes as $index)
90
			{
91
				if (strpos($row['value'], $index) !== false)
92
				{
93
					$themes[$row['id_theme']] = $index;
94
				}
95
			}
96
		}
97
	);
98
99
	return $themes;
100
}
101
102
/**
103
 * Get a basic list of themes
104
 *
105
 * @param int|int[] $themes
106
 * @return array
107
 */
108
function getBasicThemeInfos($themes)
109
{
110
	$db = database();
111
112
	$themelist = [];
113
114
	$db->fetchQuery('
115
		SELECT 
116
			id_theme, value
117
		FROM {db_prefix}themes
118
		WHERE id_member = {int:no_member}
119
			AND variable = {string:name}
120
			AND id_theme IN ({array_int:theme_list})',
121
		[
122
			'theme_list' => (array) $themes,
123
			'no_member' => 0,
124
			'name' => 'name',
125
		]
126
	)->fetch_callback(
127
		function ($row) use (&$themelist) {
128
			$themelist[$row['id_theme']] = $row['value'];
129
		}
130
	);
131
132
	return $themelist;
133
}
134
135
/**
136
 * Gets a list of all themes from the database
137
 *
138
 * @return array $themes
139
 */
140
function getCustomThemes()
141
{
142
	global $settings, $txt;
143
144
	$db = database();
145
146
	// Manually add in the default
147
	$themes = [
148
		1 => [
149
			'name' => $txt['dvc_default'],
150
			'theme_dir' => $settings['default_theme_dir'],
151
		],
152
	];
153
154
	$db->fetchQuery('
155
		SELECT 
156
			id_theme, variable, value
157
		FROM {db_prefix}themes
158
		WHERE id_theme != {int:default_theme}
159
			AND id_member = {int:no_member}
160
			AND variable IN ({string:name}, {string:theme_dir})',
161
		[
162
			'default_theme' => 1,
163
			'no_member' => 0,
164
			'name' => 'name',
165
			'theme_dir' => 'theme_dir',
166
		]
167
	)->fetch_callback(
168
		function ($row) use (&$themes) {
169
			$themes[$row['id_theme']][$row['variable']] = $row['value'];
170
		}
171
	);
172
173
	return $themes;
174
}
175
176
/**
177
 * Returns all named and installed themes paths as an array of theme name => path
178
 *
179
 * @param int[] $theme_list
180
 *
181
 * @return array
182
 */
183
function getThemesPathbyID($theme_list = [])
184
{
185
	global $modSettings;
186
187
	$db = database();
188
189
	// Nothing passed then we use the defaults
190
	if (empty($theme_list))
191
	{
192
		$theme_list = explode(',', $modSettings['knownThemes']);
193
	}
194
195
	if (!is_array($theme_list))
0 ignored issues
show
The condition is_array($theme_list) is always true.
Loading history...
196
	{
197
		$theme_list = [$theme_list];
198
	}
199
200
	// Load up any themes we need the paths for
201
	$theme_list = array_map('intval', $theme_list);
202
	$theme_paths = [];
203
	$db->fetchQuery('
204
		SELECT 
205
			id_theme, variable, value
206
		FROM {db_prefix}themes
207
		WHERE (id_theme = {int:default_theme} OR id_theme IN ({array_int:known_theme_list}))
208
			AND variable IN ({string:name}, {string:theme_dir})',
209
		[
210
			'known_theme_list' => $theme_list,
211
			'default_theme' => 1,
212
			'name' => 'name',
213
			'theme_dir' => 'theme_dir',
214
		]
215
	)->fetch_callback(
216
		function ($row) use (&$theme_paths) {
217
			$theme_paths[(int) $row['id_theme']][$row['variable']] = $row['value'];
218
		}
219
	);
220
221
	return $theme_paths;
222
}
223
224
/**
225
 * Load the installed themes
226
 * (minimum data)
227
 *
228
 * @param int[] $knownThemes available themes
229
 *
230
 * @return array
231
 */
232
function loadThemes($knownThemes)
233
{
234
	$db = database();
235
236
	// Load up all the themes.
237
	$themes = [];
238
	$db->query('', '
239
		SELECT 
240
			id_theme, value AS name
241
		FROM {db_prefix}themes
242
		WHERE variable = {string:name}
243
			AND id_member = {int:no_member}
244
		ORDER BY id_theme',
245
		[
246
			'no_member' => 0,
247
			'name' => 'name',
248 2
		]
249
	)->fetch_callback(
250 2
		function ($row) use (&$themes, $knownThemes) {
251
			$themes[] = [
252
				'id' => $row['id_theme'],
253 2
				'name' => $row['name'],
254
				'known' => in_array($row['id_theme'], $knownThemes),
255 2
			];
256
		}
257
	);
258 2
259
	return $themes;
260
}
261
262
/**
263
 * Load all themes that a package is installed in
264 2
 *
265 2
 * @param int $id id of the package we are checking
266
 *
267
 * @return array
268
 */
269
function loadThemesAffected($id)
270
{
271
	$db = database();
272 2
273 2
	$themes = [];
274 2
	$db->fetchQuery('
275 2
		SELECT 
276
			themes_installed
277 2
		FROM {db_prefix}log_packages
278
		WHERE id_install = {int:install_id}
279 2
		LIMIT 1',
280 2
		[
281
			'install_id' => $id,
282
		]
283 2
	)->fetch_callback(
284
		function ($row) use (&$themes) {
285
			$themes = explode(',', $row['themes_installed']);
286
		}
287
	);
288
289
	return $themes;
290
}
291
292
/**
293
 * Counts the theme options configured for guests
294
 *
295
 * @return array
296
 */
297
function countConfiguredGuestOptions()
298
{
299
	$db = database();
300
301
	return $db->fetchQuery('
302
		SELECT 
303
			id_theme, COUNT(*) AS value
304
		FROM {db_prefix}themes
305
		WHERE id_member = {int:guest_member}
306
		GROUP BY id_theme',
307
		[
308
			'guest_member' => -1,
309
		]
310
	)->fetch_all();
311
}
312
313
/**
314
 * Loads all available themes in the system
315
 *
316
 * - Determines count of users that are using each
317
 * - Loads variant options
318
 *
319
 * @param int $current_theme
320
 * @param int $current_member
321
 *
322
 * @return array
323
 */
324
function availableThemes($current_theme, $current_member)
325
{
326
	global $modSettings, $settings, $txt, $context;
327
328
	$db = database();
329
330
	$available_themes = [];
331
	$current_theme = (int) $current_theme;
332
	if (!empty($modSettings['knownThemes']))
333
	{
334
		$db->fetchQuery('
335
			SELECT 
336
				id_theme, variable, value
337
			FROM {db_prefix}themes
338
			WHERE variable IN ({string:name}, {string:theme_url}, {string:theme_dir}, {string:images_url}, {string:disable_user_variant})' . (!allowedTo('admin_forum') ? '
339
				AND id_theme IN ({array_string:known_themes})' : '') . '
340
				AND id_theme != {int:default_theme}
341
				AND id_member = {int:no_member}',
342
			[
343
				'default_theme' => 0,
344
				'name' => 'name',
345
				'no_member' => 0,
346
				'theme_url' => 'theme_url',
347
				'theme_dir' => 'theme_dir',
348
				'images_url' => 'images_url',
349
				'disable_user_variant' => 'disable_user_variant',
350
				'known_themes' => !empty($modSettings['theme_allow']) || allowedTo('admin_forum') ? explode(',', $modSettings['knownThemes']) : [$modSettings['theme_guests']],
351
			]
352
		)->fetch_callback(
353
			function ($row) use (&$available_themes, $current_theme) {
354
				if (!isset($available_themes[$row['id_theme']]))
355
				{
356
					$row['id_theme'] = (int) $row['id_theme'];
357
					$available_themes[$row['id_theme']] = [
358
						'id' => $row['id_theme'],
359
						'selected' => $current_theme == $row['id_theme'],
360
						'num_users' => 0
361
					];
362
				}
363
364
				$available_themes[$row['id_theme']][$row['variable']] = $row['value'];
365
			}
366
		);
367
	}
368
369
	// Okay, this is a complicated problem: the default theme is 1, but they aren't allowed to access 1!
370
	if (!isset($available_themes[$modSettings['theme_guests']]))
371
	{
372
		$available_themes[0] = [
373
			'num_users' => 0
374
		];
375
		$guest_theme = 0;
376
	}
377
	else
378
	{
379
		$guest_theme = (int) $modSettings['theme_guests'];
380
	}
381
382
	$db->fetchQuery('
383
		SELECT 
384
			id_theme, COUNT(*) AS the_count
385
		FROM {db_prefix}members
386
		GROUP BY id_theme
387
		ORDER BY id_theme DESC',
388
		[]
389
	)->fetch_callback(
390
		function ($row) use (&$available_themes, $guest_theme) {
391
			global $modSettings;
392
393
			// Figure out which theme it is they are REALLY using.
394
			if (!empty($modSettings['knownThemes']) && !in_array($row['id_theme'], explode(',', $modSettings['knownThemes'])))
395
			{
396
				$row['id_theme'] = $guest_theme;
397
			}
398
			elseif (empty($modSettings['theme_allow']))
399
			{
400
				$row['id_theme'] = $guest_theme;
401
			}
402
403
			if (isset($available_themes[$row['id_theme']]))
404
			{
405
				$available_themes[$row['id_theme']]['num_users'] += $row['the_count'];
406
			}
407
			else
408
			{
409
				$available_themes[$guest_theme]['num_users'] += $row['the_count'];
410
			}
411
		}
412
	);
413
414
	// Get any member variant preferences.
415
	$variant_preferences = [];
416
	if ($current_member > 0)
417
	{
418
		$db->fetchQuery('
419
			SELECT 
420
				id_theme, value
421
			FROM {db_prefix}themes
422
			WHERE variable = {string:theme_variant}
423
				AND id_member IN ({array_int:id_member})
424
			ORDER BY id_member ASC',
425
			[
426
				'theme_variant' => 'theme_variant',
427
				'id_member' => isset($_REQUEST['sa']) && $_REQUEST['sa'] === 'pick' ? [-1, $current_member] : [-1],
428
			]
429
		)->fetch_callback(
430
			function ($row) use (&$variant_preferences) {
431
				$variant_preferences[$row['id_theme']] = $row['value'];
432
			}
433
		);
434
	}
435
436
	// Needed to trick ThemeLoader, so we can get variant names
437
	HttpReq::instance()->post->th = true;
438
439
	foreach ($available_themes as $id_theme => $theme_data)
440
	{
441
		// Don't try to load the forum or board default theme's data... it doesn't have any!
442
		if ($id_theme === 0)
443
		{
444
			continue;
445
		}
446
447
		// The thumbnail needs the correct path.
448
		$settings['images_url'] = &$theme_data['images_url'];
449
		$theme_thumbnail_href = $theme_data['images_url'] . '/thumbnail.png';
450
451
		$txt['theme_description'] = '';
452
		$lang = new LangLoader(null, $txt, $db);
453
		$lang->changePath($theme_data['theme_dir'] . '/Languages');
454
		$lang->load('Settings', false);
455
456
		$available_themes[$id_theme]['thumbnail_href'] = str_replace('{images_url}', $settings['images_url'], $theme_thumbnail_href);
457
		$available_themes[$id_theme]['description'] = $txt['theme_description'];
458
459
		// Are there any variants?
460
		if (empty($theme_data['disable_user_variant']) || allowedTo('admin_forum'))
461
		{
462
			new ThemeLoader($theme_data['id'], false);
463
			$variants = $context['theme_instance']->getSettings();
464
465
			if (!empty($variants['theme_variants']))
466
			{
467
				$settings['theme_variants'] = $variants['theme_variants'];
468
469
				call_integration_hook('integrate_init_theme', [$id_theme, &$settings]);
470
471
				Txt::load('Settings');
472
473
				$available_themes[$id_theme]['variants'] = [];
474
				foreach ($settings['theme_variants'] as $variant)
475
				{
476
					$available_themes[$id_theme]['variants'][$variant] = [
477
						'label' => $txt['variant_' . $variant] ?? $variant,
478
						'thumbnail' => !file_exists($theme_data['theme_dir'] . '/images/thumbnail.png') || file_exists($theme_data['theme_dir'] . '/images/thumbnail_' . $variant . '.png') ? $theme_data['images_url'] . '/thumbnail_' . $variant . '.png' : ($theme_data['images_url'] . '/thumbnail.png'),
479
					];
480
				}
481
482
				// This was once a horrible ternary
483
				if (isset($_GET['vrt']))
484
				{
485
					$available_themes[$id_theme]['selected_variant'] = $_GET['vrt'];
486
				}
487
				elseif (!empty($variant_preferences[$id_theme]))
488
				{
489
					$available_themes[$id_theme]['selected_variant'] = $variant_preferences[$id_theme];
490
				}
491
				elseif (!empty($settings['default_variant']))
492
				{
493
					$available_themes[$id_theme]['selected_variant'] = $settings['default_variant'];
494
				}
495
				else
496
				{
497
					$available_themes[$id_theme]['selected_variant'] = $settings['theme_variants'][0];
498
				}
499
500
				if (!isset($available_themes[$id_theme]['variants'][$available_themes[$id_theme]['selected_variant']]['thumbnail']))
501
				{
502
					$available_themes[$id_theme]['selected_variant'] = $settings['theme_variants'][0];
503
				}
504
505
				$available_themes[$id_theme]['thumbnail_href'] = $available_themes[$id_theme]['variants'][$available_themes[$id_theme]['selected_variant']]['thumbnail'];
506
507
				// Allow themes to override the text.
508
				$available_themes[$id_theme]['pick_label'] = $txt['variant_pick'] ?? $txt['theme_pick_variant'];
509
			}
510
		}
511
	}
512
513
	// Then return it.
514
	new ThemeLoader($current_theme, true);
515
516
	return [$available_themes, $guest_theme];
517
}
518
519
/**
520
 * Counts the theme options configured for members
521
 *
522
 * @return array
523
 */
524
function countConfiguredMemberOptions()
525
{
526
	$db = database();
527
528
	return $db->fetchQuery('
529
		SELECT 
530
			COUNT(DISTINCT id_member) AS value, id_theme
531
		FROM {db_prefix}themes
532
		WHERE id_member > {int:no_member}
533
		GROUP BY id_theme',
534
		[
535
			'no_member' => 0,
536
		]
537
	)->fetch_all();
538
}
539
540
/**
541
 * Deletes all outdated options from the themes table
542
 *
543
 * @param int|string $theme : if int to remove option from a specific theme,
544
 *              if string it can be:
545
 *               - 'default' => to remove from the default theme
546
 *               - 'custom' => to remove from all the custom themes
547
 *               - 'all' => to remove from both default and custom
548
 * @param int|string $membergroups : if int a specific member
549
 *              if string a "group" of members and it can assume the following values:
550
 *               - 'guests' => obviously guests,
551
 *               - 'members' => all members with custom settings (i.e. id_member > 0)
552
 *               - 'non_default' => guests and members with custom settings (i.e. id_member != 0)
553
 *               - 'all' => any record
554
 * @param string[]|string $old_settings can be a string or an array of strings. If empty deletes all settings.
555
 */
556
function removeThemeOptions($theme, $membergroups, $old_settings = '')
557
{
558
	$db = database();
559
560
	$query_param = [];
561
562
	// The default theme is 1 (id_theme = 1)
563
	if ($theme === 'default')
564
	{
565
		$query_param = ['theme_operator' => '=', 'theme' => 1];
566
	}
567
	// All the themes that are not the default one (id_theme != 1)
568
	// @todo 'non_default' would be more explicative, though it could be confused with the one in $membergroups
569
	elseif ($theme === 'custom')
570
	{
571
		$query_param = ['theme_operator' => '!=', 'theme' => 1];
572
	}
573
	// If numeric means a specific theme
574
	elseif (is_numeric($theme))
575
	{
576
		$query_param = ['theme_operator' => '=', 'theme' => (int) $theme];
577
	}
578
579
	// Guests means id_member = -1
580
	if ($membergroups === 'guests')
581
	{
582
		$query_param += ['member_operator' => '=', 'member' => -1];
583
	}
584
	// Members means id_member > 0
585
	elseif ($membergroups === 'members')
586
	{
587
		$query_param += ['member_operator' => '>', 'member' => 0];
588
	}
589
	// Non default settings id_member != 0 (that is different from id_member > 0)
590
	elseif ($membergroups === 'non_default')
591
	{
592
		$query_param += ['member_operator' => '!=', 'member' => 0];
593
	}
594
	// all it's all
595
	elseif ($membergroups === 'all')
596
	{
597
		$query_param += ['member_operator' => '', 'member' => 0];
598
	}
599
	// If it is a number, then it means a specific member (id_member = (int))
600
	elseif (is_numeric($membergroups))
601
	{
602
		$query_param += ['member_operator' => '=', 'member' => (int) $membergroups];
603
	}
604
605
	// If array or string set up the query accordingly
606
	if (is_array($old_settings))
607
	{
608
		$var = 'variable IN ({array_string:old_settings})';
609
	}
610
	elseif (!empty($old_settings))
611
	{
612
		$var = 'variable = {string:old_settings}';
613
	}
614
	// If empty then means any setting
615
	else
616
	{
617
		$var = '1=1';
618
	}
619
620
	$db->query('', '
621
		DELETE FROM {db_prefix}themes
622
		WHERE ' . $var . ($membergroups === 'all' ? '' : '
623
			AND id_member {raw:member_operator} {int:member}') . ($theme === 'all' ? '' : '
624
			AND id_theme {raw:theme_operator} {int:theme}'),
625
		array_merge(
626
			$query_param,
627
			[
628
				'old_settings' => $old_settings
629
			]
630
		)
631
	);
632
}
633
634
/**
635
 * Update the default options for our users.
636
 *
637
 * @param array $setValues in the order: id_theme, id_member, variable name, value
638
 */
639
function updateThemeOptions($setValues)
640
{
641
	$db = database();
642
643
	$db->replace(
644
		'{db_prefix}themes',
645
		['id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'],
646
		$setValues,
647
		['id_theme', 'variable', 'id_member']
648
	);
649
}
650
651
/**
652
 * Add predefined options to the themes table.
653
 *
654
 * @param int $id_theme
655
 * @param string $options
656
 * @param string[]|string $value
657
 */
658
function addThemeOptions($id_theme, $options, $value)
659
{
660
	$db = database();
661
662
	$db->fetchQuery('
663
		INSERT INTO {db_prefix}themes
664
			(id_member, id_theme, variable, value)
665
		SELECT 
666
			id_member, {int:current_theme}, SUBSTRING({string:option}, 1, 255), SUBSTRING({string:value}, 1, 65534)
667
		FROM {db_prefix}members',
668
		[
669
			'current_theme' => $id_theme,
670
			'option' => $options,
671
			'value' => (is_array($value) ? implode(',', $value) : $value),
672
		]
673
	);
674
}
675
676
/**
677
 * Deletes a theme from the database.
678
 *
679
 * @param int $id
680
 *
681
 * @throws \ElkArte\Exceptions\Exception no_access
682
 */
683
function deleteTheme($id)
684
{
685
	$db = database();
686
687
	// Make sure we never ever delete the default theme!
688
	if ($id === 1)
689
	{
690
		throw new \ElkArte\Exceptions\Exception('no_access', false);
691
	}
692
693
	$db->query('', '
694
		DELETE FROM {db_prefix}themes
695
		WHERE id_theme = {int:current_theme}',
696
		[
697
			'current_theme' => $id,
698
		]
699
	);
700
701
	// Update the members ...
702
	$db->query('', '
703
		UPDATE {db_prefix}members
704
		SET 
705
			id_theme = {int:default_theme}
706
		WHERE id_theme = {int:current_theme}',
707
		[
708
			'default_theme' => 0,
709
			'current_theme' => $id,
710
		]
711
	);
712
713
	// ... and the boards table.
714
	$db->query('', '
715
		UPDATE {db_prefix}boards
716
		SET 
717
			id_theme = {int:default_theme}
718
		WHERE id_theme = {int:current_theme}',
719
		[
720
			'default_theme' => 0,
721
			'current_theme' => $id,
722
		]
723
	);
724
}
725
726
/**
727
 * Get the next free id for the theme.
728
 *
729
 * @return int
730
 */
731
function nextTheme()
732
{
733
	$db = database();
734
735
	// Find the newest id_theme.
736
	$result = $db->query('', '
737
		SELECT 
738
			MAX(id_theme)
739
		FROM {db_prefix}themes',
740
		[]
741
	);
742
	list ($id_theme) = $result->fetch_row();
743
	$result->free_result();
744
745
	// This will be theme number...
746
	$id_theme++;
747
748
	return $id_theme;
749
}
750
751
/**
752
 * Adds a new theme to the database.
753
 *
754
 * @param array $details
755
 */
756
function addTheme($details)
757
{
758
	$db = database();
759
760
	$db->insert('insert',
761
		'{db_prefix}themes',
762
		['id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'],
763
		$details,
764
		['id_theme', 'variable']
765
	);
766
}
767
768
/**
769
 * Get the name of a theme
770
 *
771
 * @param int $id
772
 * @return string
773
 */
774
function getThemeName($id)
775
{
776
	$db = database();
777
778
	$result = $db->query('', '
779
		SELECT 
780
			value
781
		FROM {db_prefix}themes
782
		WHERE id_theme = {int:current_theme}
783
			AND id_member = {int:no_member}
784
			AND variable = {string:name}
785
		LIMIT 1',
786
		[
787
			'current_theme' => $id,
788
			'no_member' => 0,
789
			'name' => 'name',
790
		]
791
	);
792
	list ($theme_name) = $result->fetch_row();
793
	$result->free_result();
794
795
	return $theme_name;
796
}
797
798
/**
799
 * Deletes all variants from a given theme id.
800
 *
801
 * @param int $id
802
 */
803
function deleteVariants($id)
804
{
805
	$db = database();
806
807
	$db->query('', '
808
		DELETE FROM {db_prefix}themes
809
		WHERE id_theme = {int:current_theme}
810
			AND variable = {string:theme_variant}',
811
		[
812
			'current_theme' => $id,
813
			'theme_variant' => 'theme_variant',
814
		]
815
	);
816
}
817
818
/**
819
 * Loads all the theme variable/value pairs for a member or group of members
820
 * If supplied a variable array it will only load / return those values
821
 *
822
 * @param int|int[] $theme
823
 * @param int|int[]|null $memID
824
 * @param array $options
825
 * @param string[] $variables
826
 *
827
 * @return array|array
828
 */
829
function loadThemeOptionsInto($theme, $memID = null, $options = [], $variables = [])
830
{
831
	$db = database();
832
833
	$variables = is_array($variables) ? $variables : [$variables];
0 ignored issues
show
The condition is_array($variables) is always true.
Loading history...
834
835
	// @todo the ORDER BY may or may not be necessary:
836
	// I have the feeling that *sometimes* the default order may be a bit messy,
837
	// and considering this function is not use in frequently accessed areas the
838
	// overhead for an ORDER BY should be acceptable
839
	$db->fetchQuery('
840
		SELECT 
841
			variable, value
842
		FROM {db_prefix}themes
843
		WHERE id_theme IN ({array_int:current_theme})' . ($memID === null ? '' : (is_array($memID) ? '
844
			AND id_member IN ({array_int:guest_member})' : '
845
			AND id_member = {int:guest_member}')) . (!empty($variables) ? '
846
			AND variable IN ({array_string:variables})' : '') . '
847
		ORDER BY id_theme ASC' . ($memID === null ? '' : ', id_member ASC'),
848
		[
849
			'current_theme' => is_array($theme) ? $theme : [$theme],
850
			'guest_member' => $memID,
851
			'variables' => $variables,
852
		]
853
	)->fetch_callback(
854
		function ($row) use (&$options) {
855
			$options[$row['variable']] = $row['value'];
856
		}
857
	);
858
859
	return $options;
860
}
861
862
/**
863
 * Used when installing a theme that is based off an existing theme (an therefore is dependant on)
864
 * Returns based-on theme directory values needed by the install function in ManageThemes.controller
865
 *
866
 * @param string $based_on name of theme this is based on, will do a LIKE search
867
 * @param bool $explicit_images Don't worry its not like it sounds !
868
 * @return array
869
 * @todo may be merged with something else?
870
 */
871
function loadBasedOnTheme($based_on, $explicit_images = false)
872
{
873
	$db = database();
874
875
	$request = $db->query('', '
876
		SELECT 
877
			th.value AS base_theme_dir, th2.value AS base_theme_url' . (!empty($explicit_images) ? '' : ', th3.value AS images_url') . '
878
		FROM {db_prefix}themes AS th
879
			INNER JOIN {db_prefix}themes AS th2 ON (th2.id_theme = th.id_theme
880
				AND th2.id_member = {int:no_member}
881
				AND th2.variable = {string:theme_url})' . (!empty($explicit_images) ? '' : '
882
			INNER JOIN {db_prefix}themes AS th3 ON (th3.id_theme = th.id_theme
883
				AND th3.id_member = {int:no_member}
884
				AND th3.variable = {string:images_url})') . '
885
		WHERE th.id_member = {int:no_member}
886
			AND (th.value LIKE {string:based_on} OR th.value LIKE {string:based_on_path})
887
			AND th.variable = {string:theme_dir}
888
		LIMIT 1',
889
		[
890
			'no_member' => 0,
891
			'theme_url' => 'theme_url',
892
			'images_url' => 'images_url',
893
			'theme_dir' => 'theme_dir',
894
			'based_on' => '%/' . $based_on,
895
			'based_on_path' => '%\\' . $based_on,
896
		]
897
	);
898
	$temp = $request->fetch_assoc();
899
	$request->free_result();
900
901
	return $temp;
902
}
903
904
/**
905
 * Builds a theme-info.xml file for use when a new theme is installed by copying
906
 * an existing theme
907
 *
908
 * @param string $name
909
 * @param string $version
910
 * @param string $theme_dir
911
 * @param array $theme_values
912
 */
913
function write_theme_info($name, $version, $theme_dir, $theme_values)
914
{
915
	$xml_info = '<' . '?xml version="1.0"?' . '>
916
	<theme-info xmlns="https://www.elkarte.net/xml/theme-info" xmlns:elk="https://www.elkarte.net/">
917
		<!-- For the id, always use something unique - put your name, a colon, and then the package name. -->
918
		<id>elk:' . Util::strtolower(str_replace([' '], '_', $name)) . '</id>
919
		<version>' . $version . '</version>
920
		<!-- Theme name, used purely for aesthetics. -->
921
		<name>' . $name . '</name>
922
		<!-- Author: your email address or contact information. The name attribute is optional. -->
923
		<author name="Your Name">[email protected]</author>
924
		<!-- Website... where to get updates and more information. -->
925
		<website>http://www.yourdomain.tld/</website>
926
		<!-- Template layers to use, defaults to "html,body". -->
927
		<layers>' . (empty($theme_values['theme_layers']) ? 'html,body' : $theme_values['theme_layers']) . '</layers>
928
		<!-- Templates to load on startup. Default is "index". -->
929
		<templates>' . (empty($theme_values['theme_templates']) ? 'index' : $theme_values['theme_templates']) . '</templates>
930
		<!-- Base this theme off another? Default is blank, or no. It could be "default". -->
931
		<based-on></based-on>
932
	</theme-info>';
933
934
	// Now write it.
935
	file_put_contents($theme_dir . '/theme_info.xml', $xml_info);
936
}
937