We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 4905
    • 7 Posts
    manager/processors/duplicate_content.processor.php, line 132
    for($i=0;$i<$affected;$i++) {
    	$newid +=$i;
    	duplicateTVs($myChildren[$i],$newid);
    	duplicateKeywords($myChildren[$i],$newid);
    	duplicateAccess($myChildren[$i],$newid);
    }
    


    should be changed to sth. like:

    for($i=0;$i<$affected;$i++) {
    	duplicateTVs($myChildren[$i],$newid);
    	duplicateKeywords($myChildren[$i],$newid);
    	duplicateAccess($myChildren[$i],$newid);
    	$newid++;
    }
    


    otherwise it makes incorrect calculations.

    I was trying to duplicate an entire document tree and I got some messed up TV values as a result. At first I thought it had something to do with inconsistecies in modx_site_tmplvar_contentvalues, since I had noticed, that TV values are sometimes not removed when switching between templates or deleting TVs. I wanted to clean the obsolete entries anyways, so I wrote this small module- it doesn’t look good, but maybe it could be useful to someone, so here it is:

    <?php
    
    echo '<pre>';
    $error = false;
    
    // You will need a copy of modx_site_tmplvar_contentvalues for this to work
    
    // empty table
    $sql = 'TRUNCATE TABLE modx_site_tmplvar_contentvalues_copy';
    $modx->db->query($sql);
    
    // load table
    $sql = 'INSERT INTO modx_site_tmplvar_contentvalues_copy SELECT * FROM modx_site_tmplvar_contentvalues';
    $modx->db->query($sql);
    
    // clear values for non-existing documents
    $sql = 'SELECT cv.id FROM modx_site_tmplvar_contentvalues_copy cv 
    		LEFT JOIN intl_site_content sc ON cv.contentid = sc.id
    		WHERE sc.id IS NULL';
    $res = $modx->db->query($sql);
    
    $ids = array();
    while($row = mysql_fetch_assoc($res))
    {
    	$ids[] = $row['id'];
    }
    
    $sql = sprintf("DELETE FROM modx_site_tmplvar_contentvalues_copy WHERE id IN ('%s')", implode("','", $ids));
    $modx->db->query($sql);
    $aff = mysql_affected_rows();
    if($aff)
    {
    	echo sprintf("Deleted %u values for %u non-existing documents!\n", mysql_affected_rows(), count($ids));
    	$error = true;
    }
    
    // clear TV values that no longer belong to the document
    $sql = 'SELECT contentid AS id FROM modx_site_tmplvar_contentvalues_copy';
    $res = $modx->db->query($sql);
    
    $ids = array();
    while($row = mysql_fetch_assoc($res))
    {
    	$ids[] = $row['id'];
    }
    
    $sql = sprintf("SELECT id, template FROM intl_site_content WHERE id IN ('%s') ORDER BY template, id", implode("','", $ids));
    $res = $modx->db->query($sql);
    
    $tmpl = array(); $tmplid = 0;
    while($row = mysql_fetch_assoc($res))
    {
    	if($tmplid != $row['template'])
    	{
    		$tmplid = $row['template'];
    		$tmpl[] = $tmplid;
    	}
    	$tmpl_ids[$row['template']][] = $row['id'];
    }
    
    $sql = sprintf("SELECT * FROM intl_site_tmplvar_templates WHERE templateid IN ('%s')", implode("','", $tmpl));
    $res = $modx->db->query($sql);
    
    while($row = mysql_fetch_assoc($res))
    {
    	$vars[$row['templateid']][] = $row['tmplvarid'];
    }
    
    foreach($tmpl_ids as $tmpl => $ids)
    {
    	foreach($ids as $id)
    	{
    		$sql = sprintf("DELETE FROM modx_site_tmplvar_contentvalues_copy WHERE contentid = %u AND tmplvarid NOT IN ('%s')", 
    			$id, implode("','", $vars[$tmpl]));
    		$modx->db->query($sql);
    		$aff = mysql_affected_rows();
    		if($aff)
    		{
    			echo sprintf("Deleted %u obsolete values for document ID %u!\n", mysql_affected_rows(), $id);
    			$error = true;
    		}
    	}
    }
    
    // clear duplicate TV values
    $sql = 'SELECT contentid AS id FROM modx_site_tmplvar_contentvalues_copy GROUP BY contentid, tmplvarid 
    		HAVING count(id) > 1 ORDER BY contentid ASC';
    
    $res = $modx->db->query($sql);
    
    $ids = array();
    while($row = mysql_fetch_assoc($res))
    {
    	$ids[] = $row['id'];
    }
    
    $sql = sprintf("SELECT * FROM modx_site_tmplvar_contentvalues_copy WHERE contentid IN ('%s') ORDER BY contentid, tmplvarid, value", implode("','", $ids));
    $res = $modx->db->query($sql);
    
    $veq = false; $ceq = false; $id = 0; $tmplvarid = 0; $contentid = 0; $value = ''; $del = array(); $check = array();
    while($row = mysql_fetch_assoc($res))
    {
    	if($tmplvarid == $row['tmplvarid'])
    	{
    		$veq = true;
    	}
    	else
    	{
    		$tmplvarid = $row['tmplvarid'];
    	}
    
    	if($contentid == $row['contentid'] && $veq)
    	{
    		$ceq = true;
    	}
    	else
    	{
    		$contentid = $row['contentid'];
    	}
    
    	if($value == $row['value'] && $ceq)
    	{
    		$del[] = $row['id'];
    	}
    	else if($ceq)
    	{
    		$check[] = $id;
    		$check[] = $row['id'];
    		$value = $row['value'];
    	}
    	else
    	{
    		$value = $row['value'];
    	}
    	
    	$id  = $row['id'];
    	$ceq = false;
    	$veq = false;
    }
    
    if(count($del))
    {
    	$sql = sprintf("DELETE FROM modx_site_tmplvar_contentvalues_copy WHERE id IN ('%s')", implode("','", $del));
    	$modx->db->query($sql);
    	$aff = mysql_affected_rows();
    	if($aff)
    	{
    		echo sprintf("Deleted %u duplicate values!\n", mysql_affected_rows());
    		$error = true;
    	}
    }
    
    if(count($check))
    {
    	echo "Run the following SQL statement and fix the ambiguous values manually!\n\n";
    	echo sprintf("SELECT * FROM modx_site_tmplvar_contentvalues_copy WHERE id IN ('%s') ORDER BY contentid, tmplvarid, value\n\n", implode("','", $check));
    	$error = true;
    }
    
    if(!$error)
    {
    	// empty table
    	$sql = 'TRUNCATE TABLE modx_site_tmplvar_contentvalues_copy';
    	$modx->db->query($sql);
    	
    	echo 'No errors to report!';
    }
    else
    {
    	if(!count($check))
    	{
    		echo sprintf("
    		Run the following commands to create a backup of your old data and start using the new values:\n\n
    		ALTER TABLE modx_site_tmplvar_contentvalues RENAME backup_%s_modx_site_tmplvar_contentvalues\n
    		ALTER TABLE modx_site_tmplvar_contentvalues_copy RENAME modx_site_tmplvar_contentvalues", 
    		date('d_m_Y__h_i_s', time()));
    	}
    }
    
    echo '</pre>';
    ?>
    


    I made some changes before posting it, so I hope it’s not broken smiley
      • 10487 MODX Staff
      • 1,535 Posts
      What version of MODx are you using? A fix has been put into the MODx 0.9.5 beta that corrects the duplication issue.
        Garry Nutting
        Senior Developer
        MODX, LLC

        Email: [email protected]
        Twitter: @garryn
        Web: modx.com
        • 4905
        • 7 Posts
        Well, mine is a bit older, MODx 0.9.2.1 (rev 1005), but I couldn’t find anything on the topic, so I thought I might as well mention it smiley